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