使用 Dapper 创建 Blazor Server SPA

news2025/2/21 20:54:58

介绍

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 执行复杂的数据库操作。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

编写工具调用windeployqt+ldd为msys2 Qt应用程序生成完整发布包

文章目录 概要整体架构流程技术名词解释技术细节1. 界面设计2. 递归枚举文件3. 运行windeployqt4. 运行ldd并拷贝文件5. 驱动流程 小结完整工程链接 概要 在windows下&#xff0c;动态链接库一直是发布Qt程序最为头痛的问题。在msys2环境下&#xff0c;尤其如此。msys2的winde…

ArcGIS Pro SDK (三)Addin控件 3 事件功能类

22 ArcGIS Pro 放置处理程序 22.1 添加控件 22.2 Code 放置处理程序可以实现文件拖动放置、TreeVIew、ListBox等控件拖动放置功能&#xff0c;此处新建一个停靠窗并添加一个TreeVIew&#xff0c;实现节点拖动事件&#xff1b; TestDropHandlerDockpane.xaml <UserContro…

开源项目推荐

这个资源列表集合了.NET开发领域的优秀工具、库、框架和软件等&#xff0c; 如果您目前研究开源大模型项目&#xff0c;请参考热门开源大模型项目推荐链接如下&#xff1a;https://blog.csdn.net/hefeng_aspnet/article/details/139669116 欢迎各位小伙伴收藏、点赞、留言、评论…

一文学会消息中间件的基础知识

什么是消息队列 队列数据结构 我们都学习过数据结构与算法相关的内容,消息队列从数据结构来看,就是一个由链表或是数组构成的一个先进先出的数据容器。由链表实现还是数组实现都没关系,它只要满足数据项是先进先出的特点,那么就可以认为它是一个队列结构。队列是只允许在…

个人云服务器已经被安全合规等卡脖子 建议不要买 买了必定后悔 安全是个大问题 没有能力维护

我的想法 自己买一个云服务器&#xff0c;先自己边做边学习&#xff0c;向往硅谷精神&#xff0c;财富与自由。如果能赚钱&#xff0c;就开个公司。这次到期就放弃了。 我前前后后6年花6000多元买云服务器。业余花了无数的精力&#xff0c;从2018到现在 &#xff0c;也没有折…

618购物节数码好物到底怎么选?盘点几款可闭眼入的数码好物分享

随着618购物节的热烈氛围逐渐升温&#xff0c;数码产品的选购成为了许多消费者关注的焦点。面对市场上层出不穷的新品和优惠&#xff0c;如何选择一款既符合自己需求又物超所值的数码好物&#xff0c;成为了不少人的难题&#xff0c;今天&#xff0c;我们就为大家带来几款精心挑…

QT Redis 中的实现发布/订阅功能(全网最全的教程)

Redis 介绍 Redis发布/ 订阅系统 是 Web 系统中比较常用的一个功能。简单点说就是 发布者发布消息&#xff0c;订阅者接收消息&#xff0c;这有点类似于我们的报纸/ 杂志社之类的 实现代码 #ifndef MAINWIDGET_H #define MAINWIDGET_H#include <QWidget> #include <…

【C++提高编程-09】----C++ STL之常用排序算法

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

基于单片机的无线遥控自动翻书机械臂设计

摘 要&#xff1a; 本设备的重点控制部件为单片机&#xff0c;充分实现了其自动化的目的。相关研究表明&#xff0c;它操作简单便捷&#xff0c;使残疾人在翻书时提供了较大的便利&#xff0c;使用价值性极高&#xff0c;具有很大的发展空间。 关键词&#xff1a; 机械臂&…

Django后台忘记管理员的账号

使用命令启动项目&#xff1a; python manage.py runserver输入后缀/admin&#xff0c;进入后台管理员&#xff0c;如果此时忘记你先前设置的用户名与密码怎么办&#xff1f; 终端输入&#xff1a; python manage.py shell 输入以下内容&#xff0c;并查看返回结果&#xff…

大跨度气膜综合馆有哪些优势—轻空间

1. 经济高效 材料和施工成本低 气膜综合馆的建设成本相对较低&#xff0c;主要材料为膜材和充气系统&#xff0c;不需要大量的钢筋混凝土和复杂的结构施工&#xff0c;降低了材料和施工成本。 能源消耗低 气膜馆的双层膜结构和充气系统具有良好的保温性能&#xff0c;减少了冬…

【经典爬虫案例】用Python爬取微博热搜榜!

一、爬取目标 本次爬取的是: 微博热搜榜 &#xff08;代码也可直接在下方拿&#xff09;&#xff1a; ​ 分别爬取每条热搜的&#xff1a; 热搜标题、热搜排名、热搜类别、热度、链接地址。 下面&#xff0c;对页面进行分析。 经过分析&#xff0c;此页面没有XHR链接通过&am…

Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(自定义BeanPostProcessor)

序言 之前文章有介绍采用FactoryBean的方式创建对象&#xff0c;以及使用反射创建对象。 这篇文章继续介绍Spring中创建Bean的形式之一——自定义BeanPostProcessor。 之前在介绍BeanPostProcessor的文章中有提到&#xff0c;BeanPostProcessor接口的实现中有一个Instantiatio…

Proxmox VE 超融合集群扩容后又平稳运行了170多天--不重启的话,488天了

五个节点的Proxmox VE 超融合集群&#xff0c;扩从了存储容量&#xff0c;全NVMe高速盘&#xff0c;单机4条3.7TB容量&#xff08;扩容前是两块NVMe加两块16TB的慢速SATA机械盘&#xff0c;拔掉机械盘&#xff0c;替换成两块NVMe&#xff09;&#xff0c;速度那叫一个快啊。 当…

秋招突击——6/16——复习{(单调队列优化DP)——最大子序和,背包模型——宠物小精灵收服问题}——新作{二叉树的后序遍历}

文章目录 引言复习&#xff08;单调队列优化DP&#xff09;——最大子序和单调队列的基本实现思路——求可移动窗口中的最值总结 背包模型——宠物小精灵收服问题思路分析参考思路分析 新作二叉树的后续遍历加指针调换 总结 引言 复习 &#xff08;单调队列优化DP&#xff09…

Qt实现单例模式:Q_GLOBAL_STATIC和Q_GLOBAL_STATIC_WITH_ARGS

目录 1.引言 2.了解Q_GLOBAL_STATIC 3.了解Q_GLOBAL_STATIC_WITH_ARGS 4.实现原理 4.1.对象的创建 4.2.QGlobalStatic 4.3.宏定义实现 4.4.注意事项 5.总结 1.引言 设计模式之单例模式-CSDN博客 所谓的全局静态对象&#xff0c;大多是在单例类中所见&#xff0c;在之前…

使用ant-design/cssinjs向plasmo浏览器插件的内容脚本content中注入antd的ui组件样式

之前写过一篇文章用来向content内容脚本注入antd的ui&#xff1a;https://xiaoshen.blog.csdn.net/article/details/136418199&#xff0c;但是方法就是比较繁琐&#xff0c;需要将antd的样式拷贝出来&#xff0c;然后贴到一个单独的css样式文件中&#xff0c;然后引入到内容脚…

20个超实用的VS Code扩展(2024年版)

大家好&#xff0c;今天小程给大家带来一篇关于 VS Code 扩展的文章。VS Code 这几年做得是风生水起&#xff0c;可以算得上是微软的良心产品&#xff0c;其最大的优势就是拥有众多高质量的扩展。在本文中&#xff0c;将向大家推荐一些我认为在 2024 年对开发者来说又实用又好用…

分布式技术导论 — 探索分析从起源到现今的巅峰之旅(分布式协议)

探索分析从起源到现今的巅峰之旅2 前提回顾最终一致性Clock时钟机制局限性 CAP协议CAP理论的三要素A和C机制的保障P分区容错性AP机制的保障CP机制的保障 分布式系统方向 分布式系统之ZookeeperZK的作用和职责协调服务命名服务构建高可靠服务 ZK的常见用法ZK基本原理ZK的顺序一致…