使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序

使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序

不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址

本博文翻译自:
http://l-knowtech.com/2017/08/28/first-crud-application-asp-net-core-mvc-using-entity-framework-core/


本文打算使用Entity Framework Core解释ASP.NET Core MVC中的基本创建,读取,更新和删除(CRUD)操作。我们使用Entity Framework Code First的方法开发应用程序 ,要设置ASP.NET Core MVC应用程序的开发环境,我们遵循本文中开始使用 ASP.NET Core MVC.的步骤。应用程序使用一个名为Book的实体来执行CRUD操作,并做一些简单的演示。

更多精彩内容

  1. 开始使用 ASP.NET Core MVC

创建数据库


这个应用程序采用的是Entity Framework Core 中的Code First(代码优先)方法,所以我们首先要添加Entity Framework Core ,这个应用程序使用的是SQL Server数据库,因此我们需要提供SQL Server数据库程序该,提供程序可通过名为 Microsoft.EntityFrameworkCore.SqlServer的 NuGet软件包提供。当应用程序创建时,它包括Microsoft.AspNetCore.All NuGet元包。此包还包括Microsoft.EntityFrameworkCore.SqlServer,因此我们不必安装它。

创建数据实体模型

应用程序在单个实体上执行CRUD操作,但是现在我们创建了两个实体,这些实体分别是BaseEntity和Book。BaseEntity类具有公共属性,,是其他实体的父类,并将由其他实体继承。BaseEntity类按照下面的代码片段创建。

using system;

namespace FirstCRUDApplication.DbEntities
{
    public class BaseEntity
    {
        public Int64 Id { get; set; }
        public DateTime AddedDate { get; set; }
        public DateTime ModifiedDate { get; set; }
        public string IPAddress { get; set; }
    }
}

应用程序在名为Book的实体上执行CRUD操作。现在,我们创建一个Book类并继承BaseEntity。

namespace FirstCRUDApplication.DbEntities
{
    public class Book:BaseEntity
    {
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string Author { get; set; }
        public string Publisher { get; set; }
    }
}

现在,让我们为Book实体定义配置。数据库表将使用Book实体的配置创建。定义配置有两种选择,一种是数据注释 ,另一种是Fluent API。遵循SRP原则,我们使用第二个选项Fluent API定义实体配置。下面是BookMap类的代码片段


using Microsoft.EntityFrameworkCore.Metadata.Builders;
 
namespace FirstCRUDApplication.DbEntities
{
    public class BookMap 
    {
        public BookMap(EntityTypeBuilder<Book> entityBuilder)
        {
            entityBuilder.HasKey(t => t.Id);            
            entityBuilder.Property(t => t.Name).IsRequired();
            entityBuilder.Property(t => t.ISBN).IsRequired();
            entityBuilder.Property(t => t.Author).IsRequired();
            entityBuilder.Property(t => t.Publisher).IsRequired();           
        }
    }
}

EntityTypeBuilder<T>支持Entity Framework Core的基础结构。T表示被配置的实体。它使用方法定义每个字段的配置。让我们看一下在前面的代码中使用的一些方法。

  1. HasKey:
    它设置了构成主键的实体属性。
  2. Property: 它返回一个可以用来配置实体类型属性的对象。

现在,我们创建了名为CRUDContext的上下文类。它继承自DbContext。它是实体和数据库之间的桥梁。它是一个主要类,它将数据作为对象进行交互。我们在上下文类中重写OnModelCreating方法。当我们使用Fluent API时,它定义了实体如何映射到数据库。下面是名为CRUDContext.cs的上下文类的代码片段。

using Microsoft.EntityFrameworkCore;

namespace FirstCRUDApplication.DbEntities
{
    public class CRUDContext:DbContext
    {
        public CRUDContext(DbContextOptions<CRUDContext> options) : base(options)
        {
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            new BookMap(modelBuilder.Entity<Book>());
        }
    }
}

使用EF连接数据库

我们定义了一个带有上下文的数据模型。现在,我们定义了数据库和上下文之间的连接。我们必须遵循以下步骤,在应用程序中使用上下文。

  1. 我们定义一个连接字符串,以便将上下文连接到数据库。打开appsetting.json文件,并根据以下代码片段定义连接字符串。
"ConnectionStrings": {
    "DefaultConnection": "Data Source=DESKTOP-RG33QHE;Initial Catalog=ApplicationDb;User ID=sa; Password=admin123"
  }

它类似于web.config。它存储配置级别设置,如连接字符串、SMTP、域名等。

  1. 应用程序配置从Startup类初始化。由于这个应用程序使用了Entity Framework Core,所以我们在使用中添加了两个名称空间。下面的代码片段是相同的。
using FirstCRUDApplication.DbEntities;
using Microsoft.EntityFrameworkCore;
  1. ASP.NET Core提供了内置的控制反转。在应用程序启动时,上下文注册到IoC。在此之后,使用构造函数依赖注入,上下文注入到MVC控制器中。因此,它在Startup类中注册为一个服务。下面的代码片段,用于配置上下文注册为服务的 ConfigureServices 方法。
public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddDbContext<CRUDContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }

使用EF 迁移初始化数据库

我们使用Entity Framework Core Migration来根据数据模型创建一个数据库。为了执行迁移,我们可以使用软件包管理器控制台(PMS)和命令行界面(CLI)。

Entity Framework Core工具CLI提供了 Microsoft.EntityFrameworkCore.Tool.DotNet 。要安装这个包,我们不能使用install-package命令或包管理器GUI。但是我们可以在应用程序中编辑.csproj文件,并将这个包添加到 DotNetCliToolReference,从而安装这个包,下面的XML代码是相同的。

<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" version="2.0.0" />
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
  </ItemGroup>

现在,我们需要遵循从数据模型创建新数据库的步骤。这些都是

  1. 保存更改并构建项目
  2. 打开解决方案文件夹位置。在解决方案浏览器中,右键单击该项目并从上下文菜单中选择打开文件资源管理器
  3. 如下图所示在地址栏中写入cmd命令并按Enter键。

要发起迁移,请在命令窗口中输入以下命令。

dotnet ef migrations添加了InitialCreate

图1:Entity Framework Core Migration

现在,我们将迁移应用到数据库。我们在命令窗口中输入以下命令。该命令在其中创建数据库和表。

dotnet ef database 修改

因此,我们在Entity Framework Core中使用code first方法创建了数据库


创建应用程序用户界面

现在,我们为应用程序开发用户界面。首先,我们为应用程序UI创建名为BookViewModel 的视图模型。这个模型与视图紧密地结合在一起。下面的代码片段用于视图模型。

using System.ComponentModel.DataAnnotations;

namespace FirstCRUDApplication.Models
{
    public class BookViewModel
    {
        public long Id { get; set; }       
        public string Name { get; set; }
        [Display(Name = "ISBN No")]
        public string ISBN { get; set; }
        public string Author { get; set; } 
        public string Publisher { get; set; }      
    }
}

现在,在控制器文件夹下创建一个名为 BookController的控制器。该控制器具有执行CRUD操作的操作方法。CRUDContext类实例使用依赖注入注入它的构造函数。下面的代码片段是一样的。

using FirstCRUDApplication.DbEntities;
using FirstCRUDApplication.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace FirstCRUDApplication.Controllers
{
    public class BookController : Controller
    {
        private CRUDContext context;

        public BookController(CRUDContext context)
        {
            this.context = context;
        }
        [HttpGet]
        public IActionResult Index()
        {
            IEnumerable<BookViewModel> model = context.Set<Book>().ToList().Select(b => new BookViewModel
            {
                Id= b.Id,
                Name = b.Name,
                ISBN = b.ISBN,
                Author = b.Author,
                Publisher = b.Publisher
            });
            return View("Index", model);
        }

        [HttpGet]
        public IActionResult AddEditBook(long? id)
        {
            BookViewModel model = new BookViewModel();
            if (id.HasValue)
            {
                Book book = context.Set<Book>().SingleOrDefault(c => c.Id == id.Value);
                if (book != null)
                {
                    model.Id = book.Id;
                    model.Name = book.Name;
                    model.ISBN = book.ISBN;
                    model.Author = book.Author;
                    model.Publisher = book.Publisher;
                }
            }
            return PartialView("~/Views/Book/_AddEditBook.cshtml", model);
        }

        [HttpPost]
        public IActionResult AddEditBook(long? id, BookViewModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    bool isNew = !id.HasValue;
                    Book book = isNew ? new Book
                    {
                        AddedDate = DateTime.UtcNow
                    } : context.Set<Book>().SingleOrDefault(s => s.Id == id.Value);
                    book.Name = model.Name;
                    book.ISBN = model.ISBN;
                    book.Author = model.Author;
                    book.Publisher = model.Publisher;
                    book.IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
                    book.ModifiedDate = DateTime.UtcNow;
                    if (isNew)
                    {
                        context.Add(book);
                    }
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return RedirectToAction("Index");
        }

        [HttpGet]
        public IActionResult DeleteBook(long id)
        {
            Book book = context.Set<Book>().SingleOrDefault(c => c.Id == id);
            string bookName = book.Name;         
            return PartialView("~/Views/Book/_DeleteBook.cshtml", model: bookName);
        }
        [HttpPost]
        public IActionResult DeleteBook(long id, IFormCollection form)
        {
            Book book = context.Set<Book>().SingleOrDefault(c => c.Id == id);
            context.Entry(book).State = Microsoft.EntityFrameworkCore.EntityState.Deleted;
            context.SaveChanges();
            return RedirectToAction("Index");
        }
    }
}

现在,我们为每个CRUD操作开发用户界面。视图为添加和编辑图书、图书列表和删除图书而创建。我们来一个个的来看视图。

图书清单

这是应用程序的第一个视图。它显示了清单中的所有书籍。它以表格格式显示图书数据,并有一个添加新书的选项。图书列表有编辑和删除图书的选项。它是一个名为index的索引视图.cshtml在图书文件夹的视图。下面的代码片段是一样的。

@model IEnumerable<FirstCRUDApplication.Models.BookViewModel>
@using FirstCRUDApplication.Models
@using FirstCRUDApplication.Code

<div class="top-buffer"></div>
<div class="panel panel-primary">
    <div class="panel-heading panel-head">Books</div>
    <div class="panel-body">
        <div class="btn-group">
            <a id="createEditBookModal" data-toggle="modal" asp-action="AddEditBook" data-target="#modal-action-book" class="btn btn-primary">
                <i class="glyphicon glyphicon-plus"></i>  Add Book
            </a>
        </div>
        <div class="top-buffer"></div>
        <table class="table table-bordered table-striped table-condensed">
            <thead>
                <tr>
                    <th>Name</th>                    
                    <th>ISBN</th>
                    <th>Author</th>
                    <th>Publisher</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model)
                {
                    <tr>
                        <td>@Html.DisplayFor(modelItem => item.Name)</td>
                        <td>@Html.DisplayFor(modelItem => item.ISBN)</td>
                        <td>@Html.DisplayFor(modelItem => item.Author)</td>  
                        <td>@Html.DisplayFor(modelItem => item.Publisher)</td>                       
                        <td>
                            <a id="editBookModal" data-toggle="modal" asp-action="AddEditBook" asp-route-id= "@item.Id" data-target="#modal-action-book" 
                               class="btn btn-info">
                                <i class="glyphicon glyphicon-pencil"></i>  Edit
                            </a>
                            <a id="deleteBookModal" data-toggle="modal" asp-action="DeleteBook" asp-route-id= "@item.Id" data-target="#modal-action-book" class="btn btn-danger">
                                <i class="glyphicon glyphicon-trash"></i>  Delete
                            </a>
                        </td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
</div>
@Html.Partial("_Modal", new BootstrapModel { ID = "modal-action-book", AreaLabeledId = "modal-action-book-label", Size = ModalSize.Medium })
@section scripts
{
    <script src=http://www.cnblogs.com/chen-jie/p/"~/js/book-index.js" asp-append-version="true">
}

现在,让我们运行应用程序。作为第一个请求,它使用HttpGet请求调用index()的action方法,并将UI中列出的所有图书作为响应,如图2所示。

图2:书清单界面

创建/编辑图书视图

由于创建和编辑视图都是相同的,因此我们为这两个视图创建了一个公共视图。这个视图使用相同的BookViewModel。让我们定义一个创建/编辑的图书部分视图。下面是_AddEditBook.cshtml的代码片段。

@model FirstCRUDApplication.Models.BookViewModel
@using FirstCRUDApplication.Models


<form asp-action="AddEditBook" role="form">
    @await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = String.Format("{0} Book", @Model.Id == 0 ? "Add" : "Edit") })
   
    <div class="modal-body form-horizontal">
        <div class="form-group">
            <label asp-for="Name" class="col-lg-3 col-sm-3 control-label"></label>           
            <div class="col-lg-6">
                <input asp-for="Name" class="form-control" />                
            </div>
        </div>
        <div class="form-group">
            <label asp-for="ISBN" class="col-lg-3 col-sm-3 control-label"></label>  
            <div class="col-lg-6">
                <input asp-for="ISBN" class="form-control" />                               
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Author" class="col-lg-3 col-sm-3 control-label"></label>
            <div class="col-lg-6">
                <input asp-for="Author" class="form-control" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Publisher" class="col-lg-3 col-sm-3 control-label"></label> 
            <div class="col-lg-6">
                <input asp-for="Publisher" class="form-control" /> 
            </div>
        </div>        
    </div>
  @await Html.PartialAsync("_ModalFooter", new ModalFooter { })
</form>

应用程序在弹出窗口中执行数据操作。它使用Bootstrap模型弹出。一旦它在浏览器中打开,它就会在浏览器中保存。要从缓存和加载数据中删除,我们按照以下代码片段创建一个Javascript文件。

(function ($) {
    function Book() {
        var $this = this;

        function initilizeModel() {
            $("#modal-action-book").on('loaded.bs.modal', function (e) {
            }).on('hidden.bs.modal', function (e) {
                $(this).removeData('bs.modal');
            });
        }
        $this.init = function () {
            initilizeModel();
        }
    }
    $(function () {
        var self = new Book();
        self.init();
    })
}(jQuery))

让我们运行应用程序,点击列表中的“添加书籍”按钮或“编辑”按钮。它称之为AddEditBook操作方法,它将部分视图作为响应发送。图3显示了添加/编辑图书的UI。

图3:编辑图书视图UI

删除视图

让我们执行最后的操作删除。每个图书数据在清单中都有一个delete按钮。当用户点击“删除”按钮时,弹出显示“你想删除xxx吗?”作为一个确认。这个删除弹出框有两个按钮一个是删除,另一个是取消。当用户单击弹出的删除按钮时,它会发出一个HttpPost请求,调用DeleteBook操作方法并删除书。下面是_DeleteBook.cshtml的代码片段

@model String
@using FirstCRUDApplication.Models
@using (Html.BeginForm())
{
    @Html.Partial("_ModalHeader", new ModalHeader { Heading = "Delete Book" })

    <div class="modal-body form-horizontal">
        Are you want to delete @Model?
    </div>
        @Html.Partial("_ModalFooter", new ModalFooter { SubmitButtonText="Delete"})
}

让我们运行应用程序并单击清单的Delete按钮。它显示模型中的UI,如图4中删除一本书。

图4:确认删除一本书


结论

本文使用ASP.NET Core和Entity Framework Core与code first开发应用程序并在模型弹出窗口中执行数据CRUD操作。这个演示的完整源代码可以在GitHub上下载,点击这里下载。

欢迎转载,转载请注明翻译原文出处(本文章),原文出处(原博客地址),然后谢谢观看

如果觉得我的翻译对您有帮助,请点击推荐支持:)

赞 (0) 评论 分享 ()