使用 Dapper 创建 Blazor Server SPA

介绍

Blazor 是 Microsoft 构建的一个新框架,用于使用 .NET 代码库创建交互式客户端 Web UI。

Dapper 是一个微型 ORM(对象关系映射器),可帮助将本机查询输出映射到领域类。它是由 StackOverflow 团队构建并作为开源发布的高性能数据访问系统。如果您的项目更喜欢编写存储过程或编写原始 SQL 查询,而不是使用 EntityFramework 等成熟的 ORM 工具,那么 Dapper 是您的更好选择。使用 Dapper,可以非常轻松地对数据库执行 SQL 查询并将结果映射到 C# 领域类。

我们将在 Blazor 中创建一个包含两个实体 City 和 Employee 的单页应用程序。我们将看到对这些 City 和 Employee 实体执行的所有 CRUD 操作。我们将在 City 中使用原始 SQL 查询,在 Employee 中使用存储过程。

在 SQL Server 中创建数据库、表和存储过程

请使用下面的 SQL 脚本创建新的数据库、表和存储过程。正如我之前所说的,我们将使用这些存储过程通过 Dapper 获取和存储员工数据。

USE master;
CREATE DATABASE SarathlalDb;
GO
USE SarathlalDb;
CREATE TABLE [dbo].[City] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR (250) NULL,
    [State] NVARCHAR (250) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[Employees] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR (250) NULL,
    [Department] NVARCHAR (250) NULL,
    [Designation] NVARCHAR (250) NULL,
    [Company] NVARCHAR (250) NULL,
    [CityId] INT NULL,
    CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE PROCEDURE [dbo].Add_Employee
    @Name NVARCHAR(250),
    @Department NVARCHAR(250),
    @Designation NVARCHAR(250),
    @Company NVARCHAR(250),
    @CityId INT
AS
    INSERT INTO dbo.Employees (Name, Department, Designation, Company, CityId)
    VALUES (@Name, @Department, @Designation, @Company, @CityId)
GO
CREATE PROCEDURE [dbo].Delete_Employee
    @Id INT
AS
    DELETE FROM dbo.Employees WHERE Id = @Id
GO
CREATE PROCEDURE [dbo].[Get_AllEmployees]
AS
    SELECT emp.*, c.Name CityName FROM dbo.Employees emp LEFT JOIN dbo.City c ON emp.CityId = c.Id ORDER BY emp.Name
GO
CREATE PROCEDURE [dbo].Get_SingleEmployee
    @Id INT
AS
    SELECT emp.*, c.Name CityName FROM dbo.Employees emp LEFT JOIN dbo.City c ON emp.CityId = c.Id WHERE emp.Id = @Id
GO
CREATE PROCEDURE [dbo].Update_Employee
    @Id INT,
    @Name VARCHAR(250),
    @Department VARCHAR(250),
    @Designation VARCHAR(250),
    @Company VARCHAR(250),
    @CityId INT
AS
    UPDATE dbo.Employees SET Name = @Name, Department = @Department, Designation = @Designation, Company = @Company, CityId = @CityId WHERE Id = @Id
GO

在 Visual Studio 中创建 Blazor 应用程序

打开 Visual Studio 并选择 Blazor 服务器模板来创建新项目。确保您已选择 ASP.NET Core 模板。

我们必须安装以下包才能使用 Dapper 执行数据库操作。

  • “Dapper” 和
  • “Microsoft.Data.SqlClient”
    Microsoft.Data.SqlClient 是一个新包,它支持 .NET 和 .NET Core 框架。

我们可以创建一个新类“SqlConnectionConfiguration”来从 appsettings.json 配置文件中获取 SQL 连接字符串。我们将在“Data”文件夹下创建所有 C# 类和服务。

SqlConnectionConfiguration.cs

namespace BlazorDapperSPA.Data
{
    public class SqlConnectionConfiguration
    {
        public SqlConnectionConfiguration(string value) => Value = value;
        public string Value { get; }
    }
}

我们可以在appsettings.json文件中添加连接字符串。

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SqlDbContext": "Server=MURUGAN;Database=SarathlalDb;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

创建一个具有以下属性的“City”类。

City.cs

namespace BlazorDapperSPA.Data
{
    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string State { get; set; }
    }
}

创建具有以下属性的“Employee”类。

Employee.cs

namespace BlazorDapperSPA.Data
{
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Department { get; set; }
        public string Designation { get; set; }
        public string Company { get; set; }
        public string CityId { get; set; }
    }
}

我们需要一个“EmployeeModel”类以及一个 Employee 类。因为我们需要员工列表组件中的 City 名称。我们将连接 Employee 表和 City 表,并从 City 表中获取 City 名称以及其他 Employee 表详细信息。我们可以在 EmployeeModel 类中继承 Employee 类,以利用 Employee 类中的现有属性。

EmployeeModel.cs

namespace BlazorDapperSPA.Data
{
    public class EmployeeModel : Employee
    {
        public string CityName { get; set; }
    }
}

我们可以创建一个“ICityService”接口并声明以下方法签名。

ICityService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
namespace BlazorDapperSPA.Data
{
    public interface ICityService
    {
        Task<IEnumerable<City>> GetCities();
        Task<bool> CreateCity(City city);
        Task<bool> EditCity(int id, City city);
        Task<City> SingleCity(int id);
        Task<bool> DeleteCity(int id);
    }
}

我们可以在新的类“CityService”中继承上述接口并实现方法。

CityService.cs

using Dapper;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
namespace BlazorDapperSPA.Data
{
    public class CityService : ICityService
    {
        private readonly SqlConnectionConfiguration _configuration;
        public CityService(SqlConnectionConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<bool> CreateCity(City city)
        {
            using (var conn = new SqlConnection(_configuration.Value))
            {
                const string query = @"insert into dbo.City (Name,State) values (@Name,@State)";
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync(query, new { city.Name, city.State }, commandType: CommandType.Text);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<bool> DeleteCity(int id)
        {
            using (var conn = new SqlConnection(_configuration.Value))
            {
                const string query = @"delete from dbo.City where Id=@Id";
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync(query, new { id }, commandType: CommandType.Text);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<bool> EditCity(int id, City city)
        {
            using (var conn = new SqlConnection(_configuration.Value))
            {
                const string query = @"update dbo.City set Name = @Name, State = @State where Id=@Id";
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync(query, new { city.Name, city.State, id }, commandType: CommandType.Text);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<IEnumerable<City>> GetCities()
        {
            IEnumerable<City> cities;
            using (var conn = new SqlConnection(_configuration.Value))
            {
                const string query = @"select * from dbo.City";
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    cities = await conn.QueryAsync<City>(query);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return cities;
        }
        public async Task<City> SingleCity(int id)
        {
            City city = new City();
            using (var conn = new SqlConnection(_configuration.Value))
            {
                const string query = @"select * from dbo.City where Id =@Id";
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    city = await conn.QueryFirstOrDefaultAsync<City>(query, new { id }, commandType: CommandType.Text);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return city;
        }
    }
}

我们已经在上述类中添加了 City 实体的所有逻辑。我们在 Dapper 中使用了原生 SQL 查询。

创建一个“IEmployeeService”接口并声明以下方法。

IEmployeeService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
namespace BlazorDapperSPA.Data
{
    public interface IEmployeeService
    {
        Task<IEnumerable<EmployeeModel>> GetEmployees();
        Task<bool> CreateEmployee(Employee employee);
        Task<bool> EditEmployee(int id, EmployeeModel employee);
        Task<EmployeeModel> SingleEmployee(int id);
        Task<bool> DeleteEmployee(int id);
    }
}

我们可以在新的类“EmployeeService”中继承上述接口并实现所有方法。

EmployeeService.cs

using Dapper;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
namespace BlazorDapperSPA.Data
{
    public class EmployeeService : IEmployeeService
    {
        private readonly SqlConnectionConfiguration _configuration;
        public EmployeeService(SqlConnectionConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<bool> CreateEmployee(Employee employee)
        {
            var parameters = new DynamicParameters();
            parameters.Add("Name", employee.Name, DbType.String);
            parameters.Add("Department", employee.Department, DbType.String);
            parameters.Add("Designation", employee.Designation, DbType.String);
            parameters.Add("Company", employee.Company, DbType.String);
            parameters.Add("CityId", employee.CityId, DbType.Int32);

            using (var conn = new SqlConnection(_configuration.Value))
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync("Add_Employee", parameters, commandType: CommandType.StoredProcedure);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<bool> DeleteEmployee(int id)
        {
            var parameters = new DynamicParameters();
            parameters.Add("Id", id, DbType.Int32);
            using (var conn = new SqlConnection(_configuration.Value))
            {

                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync("Delete_Employee", parameters, commandType: CommandType.StoredProcedure);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<bool> EditEmployee(int id, EmployeeModel employee)
        {
            var parameters = new DynamicParameters();
            parameters.Add("Id", id, DbType.Int32);
            parameters.Add("Name", employee.Name, DbType.String);
            parameters.Add("Department", employee.Department, DbType.String);
            parameters.Add("Designation", employee.Designation, DbType.String);
            parameters.Add("Company", employee.Company, DbType.String);
            parameters.Add("CityId", employee.CityId, DbType.Int32);
            using (var conn = new SqlConnection(_configuration.Value))
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    await conn.ExecuteAsync("Update_Employee", parameters, commandType: CommandType.StoredProcedure);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return true;
        }
        public async Task<IEnumerable<EmployeeModel>> GetEmployees()
        {
            IEnumerable<EmployeeModel> employees;
            using (var conn = new SqlConnection(_configuration.Value))
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    employees = await conn.QueryAsync<EmployeeModel>("Get_AllEmployees", commandType: CommandType.StoredProcedure);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return employees;
        }
        public async Task<EmployeeModel> SingleEmployee(int id)
        {
            var parameters = new DynamicParameters();
            parameters.Add("Id", id, DbType.Int32);
            EmployeeModel employee = new EmployeeModel();
            using (var conn = new SqlConnection(_configuration.Value))
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                try
                {
                    employee = await conn.QueryFirstOrDefaultAsync<EmployeeModel>("Get_SingleEmployee", parameters, commandType: CommandType.StoredProcedure);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            return employee;
        }
    }
}

我们可以在Startup类的“ConfigureServices”中注册ICityService和IEmployeeService。

我们还为 Blazor 服务器应用程序启用了详细错误。

Startup.cs 类中的 ConfigureServices

services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddScoped<IEmployeeService, EmployeeService>();
services.AddScoped<ICityService, CityService>();
var sqlConnectionConfiguration = new SqlConnectionConfiguration(Configuration.GetConnectionString("SqlDbContext"));
services.AddSingleton(sqlConnectionConfiguration);
services.AddServerSideBlazor(o => o.DetailedErrors = true);

创建用于 CRUD 操作的 Blazor 组件

我们可以在“Pages”文件夹中创建 City 和 Employee 的所有组件

ListCities.razor

@using BlazorDapperSPA.Data
@page "/listcities"
@inject ICityService CityService
<h2>City Details</h2>
<p>
    <a href="/addcity">Create New City</a>
</p>
@if (cities == null)
{
    <img src="./basicloader.gif" />
}
else
{
    <table class='table'>
        <thead>
            <tr>
                <th>Name</th>
                <th>State</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var city in cities)
            {
                <tr>
                    <td>@city.Name</td>
                    <td>@city.State</td>
                    <td>
                        <a href='/editcity/@city.Id'>Edit</a>
                        <a href='/deletecity/@city.Id'>Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
@code {
    IEnumerable<City> cities;
    protected override async Task OnInitializedAsync()
    {
        cities = await CityService.GetCities();
    }
}

AddCity.razor

@using BlazorDapperSPA.Data
@page "/addcity"
@inject NavigationManager NavigationManager
@inject ICityService CityService
<h2>Create City</h2>
<hr />
<form>
    <div class="row">
        <div class="col-md-8">
            <div class="form-group">
                <label for="Name" class="control-label">Name</label>
                <input for="Name" class="form-control" @bind="@city.Name" />
            </div>
            <div class="form-group">
                <label for="State" class="control-label">State</label>
                <input for="State" class="form-control" @bind="@city.State" />
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-4">
            <div class="form-group">
                <input type="button" class="btn btn-primary" @onclick="@CreateCity" value="Save"/>
                <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
            </div>
        </div>
    </div>
</form>
@code {
    City city = new City();
    protected async Task CreateCity()
    {
        await CityService.CreateCity(city);
        NavigationManager.NavigateTo("listcities");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listcities");
    }
}

EditCity.razor

@using BlazorDapperSPA.Data
@page "/editcity/{id:int}"
@inject NavigationManager NavigationManager
@inject ICityService CityService
<h2>Edit City</h2>
<hr />
<form>
    <div class="row">
        <div class="col-md-8">
            <div class="form-group">
                <label for="Name" class="control-label">Name</label>
                <input for="Name" class="form-control" @bind="@city.Name" />
            </div>
            <div class="form-group">
                <label for="State" class="control-label">State</label>
                <input for="State" class="form-control" @bind="@city.State" />
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <input type="button" class="btn btn-primary" @onclick="@UpdateCity" value="Update" />
            <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
        </div>
    </div>
</form>
@code {
    [Parameter]
    public int id { get; set; }
    City city = new City();
    protected override async Task OnInitializedAsync()
    {
        city = await CityService.SingleCity(id);
    }
    protected async Task UpdateCity()
    {
        await CityService.EditCity(id, city);
        NavigationManager.NavigateTo("listcities");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listcities");
    }
}

DeleteCity.razor

@using BlazorDapperSPA.Data
@page "/deletecity/{id:int}"
@inject NavigationManager NavigationManager
@inject ICityService CityService
<h2>Confirm Delete</h2>
<p>Are you sure you want to delete this City with Id: <b>@id</b></p>
<br />
<div class="col-md-4">
    <table class="table">
        <tr>
            <td>Name</td>
            <td>@city.Name</td>
        </tr>
        <tr>
            <td>State</td>
            <td>@city.State</td>
        </tr>
    </table>
    <div class="form-group">
        <input type="button" value="Delete" @onclick="@Delete" class="btn btn-primary" />
        <input type="button" value="Cancel" @onclick="@Cancel" class="btn" />
    </div>
</div>
@code {
    [Parameter]
    public int id { get; set; }
    City city = new City();
    protected override async Task OnInitializedAsync()
    {
        city = await CityService.SingleCity(id);
    }
    protected async Task Delete()
    {
        await CityService.DeleteCity(id);
        NavigationManager.NavigateTo("listcities");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listcities");
    }
}

我们可以为员工 CRUD 操作创建组件文件

ListEmployees.razor

@using BlazorDapperSPA.Data
@page "/listemployees"
@inject IEmployeeService EmployeeService
<h2>Employee Details</h2>
<p>
    <a href="/addemployee">Create New Employee</a>
</p>
@if (employees == null)
{
    <img src="./basicloader.gif" />
}
else
{
    <table class='table'>
        <thead>
            <tr>
                <th>Name</th>
                <th>Department</th>
                <th>Designation</th>
                <th>Company</th>
                <th>City</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var employee in employees)
            {
                <tr>
                    <td>@employee.Name</td>
                    <td>@employee.Department</td>
                    <td>@employee.Designation</td>
                    <td>@employee.Company</td>
                    <td>@employee.CityName</td>
                    <td>
                        <a href='/editemployee/@employee.Id'>Edit</a>
                        <a href='/deleteemployee/@employee.Id'>Delete</a>
                    </td>
                </tr>

            }
        </tbody>
    </table>
}
@code {
    IEnumerable<EmployeeModel> employees;
    protected override async Task OnInitializedAsync()
    {
        employees = await EmployeeService.GetEmployees();
    }
}

AddEmployee.razor

@using BlazorDapperSPA.Data
@page "/addemployee"
@inject NavigationManager NavigationManager
@inject IEmployeeService EmployeeService
@inject ICityService CityService
<h2>Create Employee</h2>
<hr />
<form>
    <div class="row">
        <div class="col-md-8">
            <div class="form-group">
                <label for="Name" class="control-label">Name</label>
                <input for="Name" class="form-control" @bind="@employee.Name" />
            </div>
            <div class="form-group">
                <label for="Department" class="control-label">Department</label>
                <input for="Department" class="form-control" @bind="@employee.Department" />
            </div>
            <div class="form-group">
                <label for="Designation" class="control-label">Designation</label>
                <input for="Designation" class="form-control" @bind="@employee.Designation" />
            </div>
            <div class="form-group">
                <label for="Company" class="control-label">Company</label>
                <input for="Company" class="form-control" @bind="@employee.Company" />
            </div>
            <div class="form-group">
                <label for="City" class="control-label">City</label>
                <select for="City" class="form-control" @bind="@employee.CityId">
                    <option value="">-- Select City --</option>
                    @foreach (var city in cities)
                    {
                        <option value="@city.Id">@city.Name</option>
                    }
                </select>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-4">
            <div class="form-group">
                <input type="button" class="btn btn-primary" @onclick="@CreateEmployee" value="Save" />
                <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
            </div>
        </div>
    </div>
</form>
@code {
    Employee employee = new Employee();
    IEnumerable<City> cities = new List<City>();
    protected override async Task OnInitializedAsync()
    {
        cities = await CityService.GetCities();
    }
    protected async Task CreateEmployee()
    {
        await EmployeeService.CreateEmployee(employee);
        NavigationManager.NavigateTo("listemployees");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listemployees");
    }
}

EditEmployee.razor

@using BlazorDapperSPA.Data
@page "/editemployee/{id:int}"
@inject NavigationManager NavigationManager
@inject IEmployeeService EmployeeService
@inject ICityService CityService
<h2>Edit Employee</h2>
<hr />
<form>
    <div class="row">
        <div class="col-md-8">
            <div class="form-group">
                <label for="Name" class="control-label">Name</label>
                <input for="Name" class="form-control" @bind="@employee.Name" />
            </div>
            <div class="form-group">
                <label for="Department" class="control-label">Department</label>
                <input for="Department" class="form-control" @bind="@employee.Department" />
            </div>
            <div class="form-group">
                <label for="Designation" class="control-label">Designation</label>
                <input for="Designation" class="form-control" @bind="@employee.Designation" />
            </div>
            <div class="form-group">
                <label for="Company" class="control-label">Company</label>
                <input for="Company" class="form-control" @bind="@employee.Company" />
            </div>
            <div class="form-group">
                <label for="City" class="control-label">City</label>
                <select for="City" class="form-control" @bind="@employee.CityId">
                    <option value="">-- Select City --</option>
                    @foreach (var city in cities)
                    {
                        <option value="@city.Id">@city.Name</option>
                    }
                </select>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <input type="button" class="btn btn-primary" @onclick="@UpdateEmployee" value="Update" />
            <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
        </div>
    </div>
</form>
@code {
    [Parameter]
    public int id { get; set; }
    EmployeeModel employee = new EmployeeModel();
    IEnumerable<City> cities = new List<City>();
    protected override async Task OnInitializedAsync()
    {
        cities = await CityService.GetCities();
        employee = await EmployeeService.SingleEmployee(id);
    }
    protected async Task UpdateEmployee()
    {
        await EmployeeService.EditEmployee(id, employee);
        NavigationManager.NavigateTo("listemployees");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listemployees");
    }
}

DeleteEmployee.razor

@using BlazorDapperSPA.Data
@page "/deleteemployee/{id:int}"
@inject NavigationManager NavigationManager
@inject IEmployeeService EmployeeService
<h2>Confirm Delete</h2>
<p>Are you sure you want to delete this Employee with Id :<b> @id</b></p>
<br />
<div class="col-md-4">
    <table class="table">
        <tr>
            <td>Name</td>
            <td>@employee.Name</td>
        </tr>
        <tr>
            <td>Department</td>
            <td>@employee.Department</td>
        </tr>
        <tr>
            <td>Designation</td>
            <td>@employee.Designation</td>
        </tr>
        <tr>
            <td>Company</td>
            <td>@employee.Company</td>
        </tr>
        <tr>
            <td>City</td>
            <td>@employee.CityName</td>
        </tr>
    </table>
    <div class="form-group">
        <input type="button" value="Delete" @onclick="@Delete" class="btn btn-primary" />
        <input type="button" value="Cancel" @onclick="@Cancel" class="btn" />
    </div>
</div>
@code {
    [Parameter]
    public int id { get; set; }
    EmployeeModel employee = new EmployeeModel();
    protected override async Task OnInitializedAsync()
    {
        employee = await EmployeeService.SingleEmployee(id);
    }
    protected async Task Delete()
    {
        await EmployeeService.DeleteEmployee(id);
        NavigationManager.NavigateTo("listemployees");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("listemployees");
    }
}

我们可以修改“NavMenu”共享组件,并将其路由到城市和员工详细信息。

NavMenu.razor

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">Blazor with Dapper</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="listcities">
                <span class="oi oi-list-rich" aria-hidden="true"></span> City data
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="listemployees">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Employee data
            </NavLink>
        </li>
    </ul>
</div>
@code {
    bool collapseNavMenu = true;
    string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

我们已经完成了全部编码。我们可以运行该应用程序了。

我们可以通过点击“城市数据”菜单链接,然后单击“创建新城市”超链接来创建一个新的城市。

保存城市详细信息后,我们可以点击“员工数据”菜单链接,然后单击“创建新员工”超链接来创建新的员工数据。

您会注意到已保存的城市数据显示在下拉菜单中。

您可以在带有编辑和删除超链接的网格中查看已保存的员工数据。

您还可以执行其他 CRUD 操作,例如编辑或删除。

结论

在本文中,我们了解了如何创建具有两个实体 City 和 Employee 的 Blazor 服务器应用程序。我们使用 Dapper ORM 通过 SQL 服务器进行数据库操作。在 City 实体中,我们使用本机 SQL 命令来检索和存储数据。而在 Employee 实体中,我们使用存储过程来执行数据库操作。您可以轻松高效地使用 Dapper 执行复杂的数据库操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/719798.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 使用Vscode的一些技巧 ROS

Ubuntu VSCode的一些设置&#xff08;ROS&#xff09; 导入工作空间 推荐只导入工作空间下的src目录 如果将整个工作空间导入VSCode&#xff0c;那么这个src就变成了次级目录&#xff0c;容易在写程序的时候把本应该添加到具体工程src目录里的代码文件给误添加到这个catkin_w…

如何使用Gitmails在版本控制主机中收集Git提交邮件

关于Gitmails Gitmails是一款能够在Git版本控制主机服务中收集Git提交电子邮件的信息收集工具&#xff0c;该工具可以帮助广大研究人员扫描和识别Git提交中包含的作者名称、电子邮件配置和版本控制主机服务是否存储了多个项目。 想要了解网络安全&#xff0c;学习网络安全知识…

SpringMVC系列九: 数据格式化与验证及国际化

SpringMVC 数据格式化基本介绍基本数据类型和字符串自动转换应用实例-页面演示方式Postman完成测试 特殊数据类型和字符串自动转换应用实例-页面演示方式Postman完成测试 验证及国际化概述应用实例代码实现注意事项和使用细节 注解的结合使用先看一个问题解决问题 数据类型转换…

数据中心分类和类别综合指南

数据中心可根据其规模、功能、所有权、层级和部署方法进行分类。以下是一些典型的数据中心类别和分类。 数据中心的分类和分级 根据尺寸 1. 小型数据中心&#xff1a;通常是为了满足对IT基础设施需求较少的组织或小型企业的需求而创建的。与大型数据中心相比&#xff0c;小型…

【Java学习笔记】枚举类与泛型

枚举类型是一种特殊的数据类型&#xff0c;之所以特殊&#xff0c;是因为它既是一种类(Class)类型&#xff0c;却又比类类型多了一些特殊的约束&#xff0c;但正是因为这些约束的存在&#xff0c;也造就了枚举类型的简洁性、安全性、便捷性。 泛型&#xff0c;即“参数化类型”…

【SPIE独立出版 | 往届均已完成EI检索】2024云计算、性能计算与深度学习国际学术会议(CCPCDL 2024)

2024云计算、性能计算与深度学习国际学术会议(CCPCDL 2024) 2024 International conference on Cloud Computing, Performance Computing and Deep Learning *CCPCDL往届均已完成EI检索&#xff0c;最快会后4个半月完成&#xff01; 一、重要信息 大会官网&#xff1a;www…

python-开学?

[题目描述] 小执&#xff1a;终于可以开学啦&#xff01;好开心啊&#xff01; 小理&#xff1a;你没看新闻吗&#xff0c;开学日期又延后了。 小执&#xff1a;&#x1d441;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&am…

Vue01-前端概述

一、前端核心分析 1.1、概述 Soc原则&#xff1a;关注点分离原则 Vue 的核心库只关注视图层&#xff0c;方便与第三方库或既有项目整合。 HTML CSS JS : 视图 &#xff1a; 给用户看&#xff0c;刷新后台给的数据 网络通信 &#xff1a; axios 页面跳转 &#xff1a; v…

Java聚合快递系统对接云洋系统快递小程序APP公众号系统源码

快递小程序的深度解析与未来展望 &#x1f69a; 引言&#xff1a;快递行业的变革与挑战 在数字化浪潮的推动下&#xff0c;快递行业正经历着前所未有的变革。随着电商的蓬勃发展&#xff0c;快递业务量呈爆发式增长&#xff0c;而传统的快递管理方式已难以满足日益增长的需求。…

我用chatgpt写了一款程序

众所周知&#xff0c;Chatgpt能够帮助人们写代码&#xff0c;前几天苏音试着完全用Chatgpt写一款Python程序 有一句话我很赞同&#xff0c;未来能代替人的不是AI&#xff0c;是会使用AI的人。 最终&#xff0c;写下来效果还不错&#xff0c;完全提升了我的办公效率。 开发前…

计算机跨考现状,两极分化现象很严重

其实我觉得跨考计算机对于一些本科学过高数的同学来说有天然的优势 只要高数能学会&#xff0c;那计算机那几本专业课&#xff0c;也能很轻松的拿下&#xff0c;而对于本科是文科类的专业&#xff0c;如果想跨考计算机&#xff0c;难度就不是一般的大了。 现在跨考计算机呈现…

了解Java的LinkedBlockingQueue

了解Java的LinkedBlockingQueue LinkedBlockingQueue是一个基于链接节点的有界阻塞队列。它实现了BlockingQueue接口&#xff0c;可以在多线程环境中安全地进行插入、移除和检查操作。LinkedBlockingQueue的容量可以在创建时指定&#xff0c;如果未指定&#xff0c;则默认容量…

AI绘画stable diffusion 模型介绍及下载、使用方法,超全的新手入门教程建议收藏!

大家好&#xff0c;我是画画的小强 今天我将继续分享AI绘画Stable Diffusion的模型、参数含义等&#xff0c;分享给各位朋友一起学习。 一、模型 Stable difusion 模型就是所谓的大模型&#xff0c;用来控制整个画面的风格走势的。 打开webui页面&#xff0c;可以看到大模型…

安卓实现圆形按钮轮廓以及解决无法更改按钮颜色的问题

1.实现按钮轮廓 在drawable文件新建xml文件 <shape xmlns:android"http://schemas.android.com/apk/res/android"<!--实现圆形-->android:shape"oval"><!--指定内部的填充色--><solid android:color"#FFFFFF"/><!-…

Mongodb介绍及window环境安装

本文主要内容为nosql数据库-MongoDB介绍及window环境安装。 目录 什么是MongoDB&#xff1f; 主要特点 MongoDB 与Mysql对应 安装MongoDB 下载MongoDB 自定义安装 创建目录 配置环境变量 配置MongoDB服务 服务改为手动 启动与关闭 安装MongoDB Shell 下载安装包 …

高考分数限制下,选好专业还是选好学校?

高考分数限制下&#xff0c;选好专业还是选好学校&#xff1f; 高考作为每年一度的盛大考试&#xff0c;不仅关乎学生们的未来&#xff0c;更承载了家庭的期望。2004年高考刚刚结束&#xff0c;许多考生和家长已经开始为填报志愿而焦虑。选好学校和专业&#xff0c;直接关系到…

LogicFlow 学习笔记——8. LogicFlow 基础 事件 Event

事件 Event 当我们使用鼠标或其他方式与画布交互时&#xff0c;会触发对应的事件。通过监听这些事件&#xff0c;可以获取其在触发时所产生的数据&#xff0c;根据这些数据来实现需要的功能。详细可监听事件见事件API。 监听事件 lf实例上提供on方法支持监听事件。 lf.on(&…

【SCAU数据挖掘】数据挖掘期末总复习题库应用题及解析

1. 给定圆的半径为e &#xff0c;令 MinPts3&#xff0c;考虑下面两幅图。 &#xff08;1&#xff09;哪些对象是核心对象? m,p,o,r(因为这些核心对象在半径e的范围内都至少包含MinPts3个对象) &#xff08;2&#xff09;哪些对象是直接密度可达的? 对象q是…

2024年【通信安全员ABC证】最新解析及通信安全员ABC证模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 通信安全员ABC证最新解析是安全生产模拟考试一点通总题库中生成的一套通信安全员ABC证模拟试题&#xff0c;安全生产模拟考试一点通上通信安全员ABC证作业手机同步练习。2024年【通信安全员ABC证】最新解析及通信安全…

vuejs3 pinia持久化存储

pinia地址&#xff1a; 开始 | Pinia 插件地址&#xff1a; 快速开始 | pinia-plugin-persistedstate 先安装pinia npm install pinia 再安装插件 安装pinia后&#xff0c;再安装这个插件 npm i pinia-plugin-persistedstate 全局中引入持久化插件 在src目录下的main…