在 Blazor WebAssembly 中使用 EF Core 7 进行 CRUD 操作

如今,作为一名开发人员,如果我们想开发任何基于 Web 的应用程序,我们可以通过多种方式开发它们。现在,我们有几种选项来构建任何基于 Web 的应用程序,例如 MVC 框架、基于 API 的结构以及任何客户端框架,例如 Angular 或 ReactJs。同样,现在我们还有另一种开发 Web 应用程序的选项,即 Blazor 框架。众所周知,Blazor 框架提供了不同的托管模型,例如 Blazor Server 或 Blazor WebAssembly。现在,在本文中,我们将演示如何在 Entity Framework 核心的帮助下使用 Blazor WebAssembly 执行基于 CRUD 的操作。

因此,在此,我们演示了如何为员工开发完整的基于 UI 的组件。 演示之后,我们可以执行以下操作 -

  • 可以查看员工名单。
  • 可以添加新员工详细信息
  • 可以更新/编辑任何现有员工详细信息
  • 可以删除任何员工记录
  • 将 Id 字段值作为路由参数传递给子页面

众所周知,Blazor Web Assembly 框架支持基于组件的概念,这是代码可重用性概念的最佳方法之一。因此,在我们的演示中,我们将创建一个名为 EmployeeInfo 的单一组件,用于员工添加、编辑或基于视图的操作。我们将在相关部分详细讨论此问题。

演示的先决条件

在开始编码工作之前,首先,我们需要了解与此应用程序相关的先决条件。主要先决条件是 -

  • .Net Framework 7.0
  • 支持 Blazor 的代码编辑器(我们将使用 Visual Studio 2022,但我们也可以使用 Visual Studio 代码)
  • 数据库应用程序(我们将使用 SQL Server)。

为演示创建数据库结构

在开始使用 Blazor WebAssembly 项目之前,首先,我们需要为示例创建数据库表结构。为此,我们使用 SQL Server 数据库。因此,我们需要在数据库中创建一个名为“Employees”的表,如下所示。

CREATE TABLE [dbo].[Employees](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Code] [nvarchar](20) NOT NULL,
    [FullName] [nvarchar](100) NULL,
    [DOB] [datetime] NOT NULL,
    [Address] [nvarchar](200) NULL,
    [City] [nvarchar](100) NULL,
    [State] [nvarchar](100) NULL,
    [Country] [nvarchar](100) NULL,
    [PostalCode] [nvarchar](15) NULL,
    [EmailId] [nvarchar](100) NULL,
    [PhoneNo] [nvarchar](50) NULL,
    [JoiningDate] [datetime] NULL,
    CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)

现在,出于测试目的,我们将在表中插入一条记录 -

SET IDENTITY_INSERT [dbo].[Employees] ON
GO
INSERT [dbo].[Employees] ([Id], [Code], [FullName], [DOB], [Address], [City], [State], [Country], [PostalCode], [EmailId], [PhoneNo], [JoiningDate]) VALUES (1, N'E0001', N'NILAY SHARMA', CAST(N'1998-05-05T00:00:00.000' AS DateTime), N'CENTRAL ROAD', N'KOLKATA', N'WB', N'INDIA', N'700001', N'NILAY@YAHOO.COM', N'9830198301', CAST(N'2021-10-05T00:00:00.000' AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[Employees] OFF
GO

创建员工列表页面

步骤1. 首先,打开 Microsoft Visual Studio 2022,然后单击创建新项目。

步骤2. 现在选择 Blazor WebAssembly App 选项并单击下一步按钮。

步骤3. 在下一个窗口中,提供项目名称,然后单击下一步按钮。

步骤4. 现在,选择框架版本.Net7,然后单击创建按钮。

步骤5. 现在打开客户端项目共享文件夹下的NavMenu.razor页面和下面的代码来创建员工的链接。

<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="employee/index">
                <span class="oi oi-plus" aria-hidden="true"></span> Employee List
            </NavLink>
        </div>
    </nav>
</div>

步骤6. 现在,选择共享项目并将下面提到的 Nuget 包添加到该项目。

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools

步骤7. 现在,在共享项目中,添加一个名为 Models 的新文件夹,并添加名为 Employee.cs 的新文件,如下所示。

public class Employee
{
    public int Id { get; set; }

    [Required]
    public string Code { get; set; }

    [Required]
    public string FullName { get; set; }

    [Required]
    [DataType(DataType.Date)]
    public DateTime DOB { get; set; }

    public string? Address { get; set; }

    [Required]
    public string City { get; set; }

    [Required]
    public string State { get; set; }

    [Required]
    public string Country { get; set; }

    [Required]
    public string PostalCode { get; set; }

    [Required]
    public string EmailId { get; set; }

    [Required]
    public string PhoneNo { get; set; }

    [Required]
    [DataType(DataType.Date)]
    public DateTime JoiningDate { get; set; }
}

步骤8. 现在,在共享文件夹下添加另一个名为 DBContexts 的新文件夹,并创建一个名为 SQLDBContext.cs 的新文件并在其中添加以下代码。

public partial class SQLDBContext: DbContext
{
    public SQLDBContext()
    {
    }

    public SQLDBContext(DbContextOptions<SQLDBContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Employee> Employees { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer("Server=DEB-HP-NOTEBOOK;Database=PracticeDB;user id=debas; Trusted_Connection=True; MultipleActiveResultSets=true; Encrypt=False;");
        }
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

    }
}

步骤9. 选择服务器项目下的控制器文件夹并添加一个名为 EmployeeController.cs 的新控制器。

步骤10. 现在,在员工控制器中添加以下代码来获取员工列表数据。

[Route("api/[controller]")]
[ApiController]
public class EmployeeController: ControllerBase
{
    private readonly SQLDBContext _dbContext;

    public EmployeeController(SQLDBContext context)
    {
        _dbContext = context;
    }

    [Route("GetEmployees")]
    [HttpGet]
    public async Task<IList<Employee>> GetEmployees()
    {
        try
        {
            var _data = await _dbContext.Employees.ToListAsync();
            return _data;
        }
        catch (Exception ex)
        {
            throw (ex);
        }
    }

    [Route("GetEmployee/{id}")]
    [HttpGet]
    public async Task<Employee> GetEmployee(int id)
    {
        try
        {
            var _data = await _dbContext.Employees.FindAsync(id);
            return _data;
        }
        catch (Exception ex)
        {
            throw (ex);
        }
    }

    [Route("SaveEmployee")]
    [HttpPost]
    public async Task<IActionResult> SaveEmployee(Employee employee)
    {
        try
        {
            if (_dbContext.Employees == null)
            {
                return Problem("Entity set 'AppDbContext.Employee'  is null.");
            }

            if (employee != null)
            {
                _dbContext.Add(employee);
                await _dbContext.SaveChangesAsync();

                return Ok("Save Successfully!!");
            }
        }
        catch (Exception ex)
        {
            throw (ex);
        }

        return NoContent();
    }

    [Route("UpdateEmployee")]
    [HttpPost]
    public async Task<IActionResult> UpdateEmployee(Employee employee)
    {
        _dbContext.Entry(employee).State = EntityState.Modified;

        try
        {
            await _dbContext.SaveChangesAsync();
            return Ok("Update Successfully!!");
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!EmployeeExists(employee.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();
    }


    [HttpDelete("DeleteEmployee/{id}")]
    public async Task<IActionResult> DeleteProduct(int id)
    {
        if (_dbContext.Employees == null)
        {
            return NotFound();
        }
        var product = await _dbContext.Employees.FindAsync(id);
        if (product == null)
        {
            return NotFound();
        }

        _dbContext.Employees.Remove(product);
        await _dbContext.SaveChangesAsync();

        return NoContent();
    }

    private bool EmployeeExists(int id)
    {
        return (_dbContext.Employees?.Any(e => e.Id == id)).GetValueOrDefault();
    }
}

步骤11. 我们的员工 GetAll API 端点已准备好检索所有员工列表数据。

步骤12. 现在,返回到客户端项目并在Pages文件夹下添加一个名为Employee的新文件夹。

步骤13. 现在,添加一个名为EmployeeList的新Razor组件,如下所示。

步骤14. 步骤14. 现在,在EmployeeList.razor组件中添加以下代码。

@page "/employee/index"
@using employee_crud_ops.Shared.Models
@inject HttpClient Http

<h3>Employee List</h3>

<h4 style="color:blue;">
    Wants to Add New Employee? Click on <a href="/employee/create">Add Employee</a>
</h4>
<table class="table">
    <thead>
        <tr>
            <th>Code</th>
            <th>Full Name</th>
            <th>Date of Birth</th>
            <th>State</th>
            <th>City</th>
            <th>Joining Date</th>
        </tr>
    </thead>
    <tbody>
        @if (employees == null)
        {
            <tr>
                <td colspan="8" align="center">No Data Found</td>
            </tr>
        }
        else
        {
            @foreach (var employee in employees)
            {
                <tr>
                    <td width="10%">@employee.Code</td>
                    <td width="25%">employee.FullName</td>
                    <td width="10%">@employee.DOB.ToShortDateString()</td>
                    <td width="15%">@employee.State</td>
                    <td width="15%">@employee.City</td>
                    <td width="10%">@employee.JoiningDate.ToShortDateString()</td>

                </tr>
            }
        }
    </tbody>
</table>

@code {
    private Employee[]? employees;

    protected override async Task OnInitializedAsync()
    {
        await this.FetEmployees();
    }

    private async Task FetEmployees()
    {
        employees = await Http.GetFromJsonAsync<Employee[]>("/api/employee/getemployees");
    }
}

步骤15. 现在,运行应用程序,然后检查员工链接。


创建添加/编辑相关组件
现在,在本节中,我们将演示如何根据员工记录执行添加或编辑操作。为此,我们将首先创建一个 EmployeeInfo 组件,该组件将用作两个操作(即添加和编辑)的通用组件。此组件不会执行任何 API 调用。它仅接受值作为输入参数并将数据绑定到控件中。此外,当用户单击保存按钮时,它会引发一个 EventCallback 方法,以便相关组件可以捕获该请求并按照其逻辑执行。

步骤1. 现在,在客户端项目的员工文件夹下添加另一个名为EmployeeInfo.razor的新组件文件,然后添加以下代码。

@using employee_crud_ops.Shared.Models

<h3>@HeaderText</h3>
<hr />

<div style="width:60%;">

    <EditForm Model="Employee" OnValidSubmit="OnValidSubmit">
        <DataAnnotationsValidator />

        <div class="row mb-3">
            <label for="inputCode" class="col-sm-2 col-form-label">Employee Code</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empcode" @bind-Value="@Employee.Code" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.Code)" />
            </div>
        </div>
        <div class="row mb-3">
            <label for="inputName" class="col-sm-2 col-form-label">Employee Name</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empname" @bind-Value="@Employee.FullName" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.FullName)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputDOB" class="col-sm-2 col-form-label">Date Of Birth</label>
            <div class="col-sm-10">
                <InputDate class="form-control" id="empdob" @bind-Value="@Employee.DOB" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.DOB)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputJoinDate" class="col-sm-2 col-form-label">Joining Date</label>
            <div class="col-sm-10">
                <InputDate class="form-control" id="empjoindate" @bind-Value="@Employee.JoiningDate" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.JoiningDate)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputAddress" class="col-sm-2 col-form-label">Address</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empaddr" @bind-Value="@Employee.Address" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.Address)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputCity" class="col-sm-2 col-form-label">City</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empcity" @bind-Value="@Employee.City" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.City)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputState" class="col-sm-2 col-form-label">State</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empstate" @bind-Value="@Employee.State" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.State)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputCountry" class="col-sm-2 col-form-label">Country</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empcountry" @bind-Value="@Employee.Country" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.Country)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputpin" class="col-sm-2 col-form-label">Postal Code</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="emppicode" @bind-Value="@Employee.PostalCode" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.PostalCode)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputEmail" class="col-sm-2 col-form-label">Email</label>
            <div class="col-sm-10">
                <InputText type="email" class="form-control" id="empemail" @bind-Value="@Employee.EmailId" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.EmailId)" />
            </div>
        </div>

        <div class="row mb-3">
            <label for="inputPhone" class="col-sm-2 col-form-label">Phone No</label>
            <div class="col-sm-10">
                <InputText type="text" class="form-control" id="empphone" @bind-Value="@Employee.PhoneNo" disabled=@ReadOnlyMode />
                <ValidationMessage For="@(() => Employee.PhoneNo)" />
            </div>
        </div>

        <a class="btn btn-danger" tabindex="-1" role="button" aria-disabled="true" href="employee/index">Back To Employee List</a>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

        @if (ReadOnlyMode == false)
        {
            <button type="submit" class="btn btn-primary">@(EmployeeId >0 ? "Update" : "Save")</button>
        }
    </EditForm>
</div>

@code {
    [Parameter] public int EmployeeId { get; set; }
    [Parameter] public string HeaderText { get; set; }
    [Parameter] public Employee Employee { get; set; }
    [Parameter] public bool ReadOnlyMode { get; set; }

    [Parameter] public EventCallback OnValidSubmit { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        Console.WriteLine(ReadOnlyMode);
    }

}

步骤2. 在上面的组件中,我们定义了四个不同的输入参数。

  1. EmployeeId: 主要用于更改Save或Update方法的按钮标题。
  2. HeaderText: 将用于提供页面标题目的。
  3. Employee: 员工模型类的对象。它携带更新时的现有数据。
  4. ReadOnlyMode: 仅用于查看目的。

步骤3. 现在,添加另一个名为 AddEmployee.razor 的组件,并在那里添加以下代码 -

@page "/employee/create"
@page "/employee/edit/{employeeId:int}"

@using employee_crud_ops.Shared.Models
@inject HttpClient Http
@inject NavigationManager navigationManager

@if (employeeId > 0)
{
    <EmployeeInfo EmployeeId="employeeId" HeaderText="Update Employee Details" Employee="employee" OnValidSubmit="UpdateEmployee"></EmployeeInfo>
}
else
{
    <EmployeeInfo EmployeeId="0" HeaderText="Add Employee Details" Employee="employee" OnValidSubmit="CreateEmployee"></EmployeeInfo>
}

@code {
    private Employee employee = new Employee();

    [Parameter] public int employeeId { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (employeeId > 0)
            employee = await Http.GetFromJsonAsync<Employee>($"/api/employee/getemployee/{employeeId}");
    }

    private async Task CreateEmployee()
    {
        Console.WriteLine(employee.Code);

        var result = await Http.PostAsJsonAsync("/api/employee/saveemployee", employee);
        if (result != null && result.StatusCode == System.Net.HttpStatusCode.OK)
        {
            navigationManager.NavigateTo("employee/index");
        }
    }

    private async Task UpdateEmployee()
    {
        Console.WriteLine(employee.Code);

        var result = await Http.PostAsJsonAsync("/api/employee/updateemployee", employee);
        if (result != null && result.StatusCode == System.Net.HttpStatusCode.OK)
        {
            navigationManager.NavigateTo("employee/index");
        }
    }
}

步骤4. 上述组件也将在编辑现有记录时使用。这就是为什么我们为该组件使用两个不同的路由索引。

步骤5. 现在,运行应用程序,然后单击员工列表视图中的添加员工链接按钮。

步骤6. 现在,对于编辑按钮,在 EmployeeList 表视图中添加以下代码。

<td width="7%">
    <a href="@GetEditEmployeeViewUrl(@employee)" class="btn btn-primary" tabindex="-1" role="button" aria-disabled="true">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
            <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z">.
            </path>
        </svg> Edit
    </a>
</td>

步骤7. 现在,在EmployeeList的代码部分添加以下方法。

private string GetEditEmployeeViewUrl(Employee employee)
{
    return $"employee/edit/{employee.Id}";
}

步骤8. 现在,运行应用程序以检查编辑功能。

执行删除操作

在本节中,我们将演示如何从列表页面执行删除操作。对于删除操作,当用户单击“删除”按钮时,我们需要实现用户的一次确认。但在 Blazor 中,我们不能直接使用任何基于 JavaScript 的模态窗口。如果我们想使用它,我们可以借助 JS 引擎注入来使用它。为此,首先,打开 EmployeeList.razor 组件并在开始部分添加下面的代码行。

@page "/employee/index"
@using employee_crud_ops.Shared.Models
@inject HttpClient Http
@inject IJSRuntime JsRuntime

现在,在表格部分添加下面的代码来生成删除按钮和编辑按钮。

<td width="8%">
    <a class="btn btn-danger" tabindex="-1" role="button" aria-disabled="true" @onclick="_ => DeleteEmployee(employee)">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
            <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"></path>
        </svg> Delete
    </a>
</td>

现在,在代码部分添加下面的代码来调用 Delete 方法。

private async Task DeleteEmployee(Employee employee)
{
    bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", $"Are you sure to Delete the Employee Record : {employee.Code}?"); // Confirm

    if (confirmed)
    {
        var result = await Http.DeleteAsync($"/api/employee/deleteemployee/{employee.Id}");
        if (result != null && result.StatusCode == System.Net.HttpStatusCode.OK)
        {
            await this.FetEmployees();
        }
    }
}

现在,运行应用程序来检查删除操作。

结论

因此,在本文中,我们讨论使用 Blazor Web Assembly 以及 Entity Framework Core 7.0 的基本 CRUD 操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢.锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值