使用 MVC 中的 Entity Framework 5.0 Code First 方法进行 CRUD 操作






4.84/5 (33投票s)
在本文中,您将学习如何使用 MVC 中的 Entity Framework 5.0 Code First 方法执行 CRUD 操作。
引言
本文介绍了 MVC 应用程序中的 Entity Framework 5.0 Code First 方法。我们正在开发一个针对 Publisher 和 Book 实体的应用程序,我们可以在其上执行创建 (Create)、读取 (Read)、更新 (Update) 和删除 (Delete) 操作。我们创建这两个实体,并使用 Fluent API 在它们之间建立一对多关系。
ADO.NET Entity Framework 是 .NET Framework 中包含的一个对象关系映射器 (ORM)。它基本上会根据数据库表生成业务对象和实体。它提供基本的 CRUD 操作,可以轻松管理实体之间的关系,并支持实体之间的继承关系。
在使用 EF 时,我们与实体模型进行交互,而不是与应用程序的关系数据库模型进行交互。这种抽象允许我们专注于业务行为和实体之间的关系。我们使用 Entity Framework 数据上下文来执行查询。当调用 CRUD 操作之一时,Entity Framework 会生成执行该操作所需的 SQL。
学习使用 Entity Framework 进行 MVC 的路线图
- 使用 Code First 方法和 Fluent API 在 Entity Framework 中建立关系。
- Entity Framework 的 Code First 迁移
- 使用 MVC 中的 Entity Framework 5.0 Code First 方法进行 CRUD 操作
- 在 MVC 中使用存储库模式进行 CRUD 操作
- 在 MVC 中使用通用存储库模式和工作单元进行 CRUD 操作
- 使用通用存储库模式和控制反转 (Ninject) 在 MVC 中执行 CRUD 操作
背景
要创建此应用程序,我们应该对 System.Data.Entity
命名空间中的 DbContext
类有基本了解。我们也应该熟悉视图,因为在本文中我不会为每个操作方法描述视图,所以您可以根据操作方法创建视图,或者可以使用脚手架模板为 Edit、List、Create、Delete 和 Details 创建视图。
我们需要将 Entity Framework Nuget 包安装到我们的应用程序中。当我们安装 Entity Framework Nuget 包时,会在我们的应用程序中添加两个引用 (System.Data.Entity
和 EntityFramework)。之后,我们就可以使用 Entity Framework 执行 CRUD 操作了。
Entity Framework Code First 方法
无论您是否已有数据库,都可以编写自己的类和属性(也称为 POCO - Plain Old CLR Objects),这些类和属性对应于表和列,并可以在没有 .edmx 文件的情况下与 Entity Framework 一起使用。在这种方法中,Entity Framework 不利用任何配置文件(*.edmx 文件)来存储数据库架构,因为映射 API 使用这些约定在运行时动态生成数据库架构。目前,Entity Framework Code First 方法不支持映射到存储过程。可以使用 ExecuteSqlCommand() 和 SqlQuery() 方法来执行存储过程。
要理解 Entity Framework Code First 方法,您需要创建一个具有两个实体的 MVC 应用程序,一个实体是 Publisher,另一个是 Book。所以让我们一步一步地看一个例子。
要创建您的 MVC 应用程序,在 Visual Studio 中选择“文件”->“新建”->“项目...”,然后选择“MVC 4 应用程序”,然后选择“空应用程序”。
创建模型类
我们在 Models 文件夹下为 Publisher 和 Book 创建类,这些类用作实体和实体集。这些类将与数据库进行映射,因为我们正在使用 Code First 方法,并且这些类将使用 Entity Framework 的 DbContext
类在数据库中创建表。所以让我们逐一看看这些类。
Publisher
类位于 Models 文件夹下;该文件名是 Publisher.cs,如下所示:
using System.Collections.Generic;
namespace ExampleCodeFirstApproch.Models
{
public class Publisher
{
public int PublisherId { get; set; }
public string PublisherName { get; set; }
public string Address { get; set; }
public ICollection<book> Books { get; set; }
}
}</book>
Book
类位于 Models 文件夹下;该文件名是 Book.cs,如下所示:
namespace ExampleCodeFirstApproch.Models
{
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public int PublisherId { get; set; }
public Publisher Publisher { get; set; }
}
}
创建数据访问层
本文的这一部分是本文以及 Code First 方法的核心。首先,我们需要一个连接字符串,以便应用程序可以连接到我们的数据库。我们在 web.config 文件中创建一个连接。我将连接字符串名称指定为 DbConnectionString
,您可以随意命名,但请记住它,因为我们将在上下文类中使用它。
<connectionStrings>
<add name="DbConnectionString"
connectionString="Data Source=sandeepss-PC;Initial Catalog=CodeFirst;User ID=sa;
Password=*******" providerName="System.Data.SqlClient" />
</connectionStrings>
我们已经有了 Publisher
和 Book
这两个类,现在我们将创建一个上下文类。我们在 Models 文件夹下创建一个 LibraryContext
类,该文件名是 LibraryContext.cs。此类继承 DbContext
,因此我们可以使用 LibraryContext
类的对象来使用 DbContext
类的方法,如下所示:
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
namespace ExampleCodeFirstApproch.Models
{
public class LibraryContext :DbContext
{
public LibraryContext()
: base("name=DbConnectionString")
{
}
public DbSet<Publisher> Publishers { get; set; }
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Publisher>().HasKey(p => p.PublisherId);
modelBuilder.Entity<Publisher>().Property(c => c.PublisherId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Book>().HasKey(b => b.BookId);
modelBuilder.Entity<Book>().Property(b => b.BookId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Book>().HasRequired(p => p.Publisher)
.WithMany(b => b.Books).HasForeignKey(b=>b.PublisherId);
base.OnModelCreating(modelBuilder);
}
}
}
我们继承 DbContext
类的 LibraryContext
类已经准备好了。LibraryContext
类包含一个三部分构造函数、DbSet
属性和一个 OnModelCreating
方法。让我们逐一查看。
构造函数:这是一个不带任何参数的空构造函数,换句话说,它是默认构造函数,但它继承了基类的单字符串参数化构造函数。此构造函数使用给定的字符串作为数据库的名称(如我们所用)或连接字符串来构造新的上下文实例。这里 DbConnectionString
是应用程序 web.config 文件中定义的连接字符串的名称。
public LibraryContext(): base("name=DbConnectionString")
{
}
属性:在 Code First 工作流程开发时,您会定义一个派生的 DbContext
,它代表与数据库的会话,并为模型中的每种类型公开一个 DbSet
。Code First 示例中显示的常见情况是,DbContext
具有针对模型实体类型的公共自动 DbSet
属性。
public DbSet<Publisher> Publishers { get; set; }
public DbSet<Book> Books { get; set; }
Dbset
属性代表一个实体集,用于执行创建、读取、更新和删除操作。当实体类型在编译时未知时,可以使用非泛型版本的 DbSet<TEntity>
。这里我们使用实体的属性的复数名称,这意味着您的表将在数据库中以该特定实体的名称创建。
方法:LibraryContext
类有一个重写的 OnModelCreating
方法。此方法在派生上下文的模型已初始化但模型尚未锁定并用于初始化上下文之前被调用。此方法的默认实现不执行任何操作,但可以在派生类中重写它,以便在模型锁定之前对其进行进一步配置。基本上,在此方法中,我们配置将由模型创建的数据库表或这些表之间的定义的任何关系。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Publisher>().HasKey(p => p.PublisherId);
modelBuilder.Entity<Publisher>().Property(c => c.PublisherId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Book>().HasKey(b => b.BookId);
modelBuilder.Entity<Book>().Property(b => b.BookId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Book>().HasRequired(p => p.Publisher)
.WithMany(b => b.Books).HasForeignKey(b=>b.PublisherId);
base.OnModelCreating(modelBuilder);
}
此方法接受一个参数,即 DbModelBuilder
对象。DbModelBuilder
类将 POCO 类映射到数据库架构。此方法仅在创建派生上下文的第一个实例时调用一次。然后缓存该上下文的模型,并供应用程序域中所有后续的上下文实例使用。可以通过在给定的 ModelBuidler
上设置 ModelCaching
属性来禁用此缓存,但这可能会严重降低性能。通过直接使用 DbModelBuilder
和 DbContext
类可以获得对缓存的更多控制。
使用 Fluent API 配置/映射属性
LibraryContext
类下的 OnModelCreating()
方法使用 Fluent API 来映射和配置表中的属性。所以让我们逐一查看 OnModelCreating()
方法中使用的每个方法。
modelBuilder.Entity<Book>().HasRequired(p => p.Publisher)
.WithMany(b => b.Books).HasForeignKey(b=>b.PublisherId);
HasKey()
:Haskey()
方法配置表的主键。Property()
:Property
方法配置属于实体或复杂类型的每个属性的属性。它用于获取给定属性的配置对象。配置对象上的选项特定于正在配置的类型;例如,IsUnicode
仅对字符串属性可用。HasDatabaseGeneratedOption
:它配置属性的值如何由数据库生成。DatabaseGeneratedOption.Identity
:DatabaseGeneratedOption
是数据库注释。它枚举了一个数据库生成选项。DatabaseGeneratedOption.Identity
用于通过唯一值在表中创建自增列。- 使用以下表达式定义
Publisher
和Book
之间的外键关系
为 CRUD 操作创建控制器
现在我们在应用程序的 Controllers 文件夹下创建两个控制器,一个用于 Publisher CRUD 操作 (PublisherController.cs),另一个用于 Book CRUD 操作 (BookController.cs)。所以这是每个控制器的代码。
Publisher 控制器在 Controllers 文件夹下的 PublisherController.cs 文件中
using System.Linq;
using System.Web.Mvc;
using ExampleCodeFirstApproch.Models;
namespace ExampleCodeFirstApproch.Controllers
{
public class PublisherController : Controller
{
LibraryContext objContext;
public PublisherController()
{
objContext = new LibraryContext();
}
#region List and Details Publisher
public ActionResult Index()
{
var publishers = objContext.Publishers.ToList();
return View(publishers);
}
public ViewResult Details(int id)
{
Publisher publisher =
objContext.Publishers.Where(x=>x.PublisherId==id).SingleOrDefault();
return View(publisher);
}
#endregion
#region Create Publisher
public ActionResult Create()
{
return View(new Publisher());
}
[HttpPost]
public ActionResult Create(Publisher publish)
{
objContext.Publishers.Add(publish);
objContext.SaveChanges();
return RedirectToAction("Index");
}
#endregion
#region edit publisher
public ActionResult Edit(int id)
{
Publisher publisher = objContext.Publishers.Where(
x => x.PublisherId == id).SingleOrDefault();
return View(publisher);
}
[HttpPost]
public ActionResult Edit(Publisher model)
{
Publisher publisher = objContext.Publishers.Where(
x => x.PublisherId == model.PublisherId).SingleOrDefault();
if (publisher != null)
{
objContext.Entry(publisher).CurrentValues.SetValues(model);
objContext.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
#endregion
#region Delete Publisher
public ActionResult Delete(int id)
{
Publisher publisher = objContext.Publishers.Find(id);
//.Where(x => x.PublisherId == id).SingleOrDefault();
return View(publisher);
}
[HttpPost]
public ActionResult Delete(int id, Publisher model)
{
var publisher =
objContext.Publishers.Where(x => x.PublisherId == id).SingleOrDefault();
if (publisher != null)
{
objContext.Publishers.Remove(publisher);
objContext.SaveChanges();
}
return RedirectToAction("Index");
}
#endregion
}
}
Book 控制器在 Controllers 文件夹下的 BookController.cs 文件中
using System.Linq;
using System.Web.Mvc;
using ExampleCodeFirstApproch.Models;
namespace ExampleCodeFirstApproch.Controllers
{
public class BookController : Controller
{
LibraryContext objContext;
public BookController()
{
objContext = new LibraryContext();
}
#region List and Details Book
public ActionResult Index()
{
var books = objContext.Books.ToList();
return View(books);
}
public ViewResult Details(int id)
{
Book book = objContext.Books.Where(x=>x.BookId==id).SingleOrDefault();
return View(book);
}
#endregion
#region Create Publisher
public ActionResult Create()
{
return View(new Book());
}
[HttpPost]
public ActionResult Create(Book book)
{
objContext.Books.Add(book);
objContext.SaveChanges();
return RedirectToAction("Index");
}
#endregion
#region Edit Book
public ActionResult Edit(int id)
{
Book book = objContext.Books.Where(x => x.BookId == id).SingleOrDefault();
return View(book);
}
[HttpPost]
public ActionResult Edit(Book model)
{
Book book = objContext.Books.Where(x => x.BookId == model.BookId).SingleOrDefault();
if (book != null)
{
objContext.Entry(book).CurrentValues.SetValues(model);
objContext.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
#endregion
#region Delete Book
public ActionResult Delete(int id)
{
Book book = objContext.Books.Find(id);
return View(book);
}
[HttpPost]
public ActionResult Delete(int id, Publisher model)
{
var book = objContext.Books.Where(x => x.BookId == id).SingleOrDefault();
if (book != null)
{
objContext.Books.Remove(book);
objContext.SaveChanges();
}
return RedirectToAction("Index");
}
#endregion
}
}
Publisher 和 Book 控制器都已准备就绪,使用脚手架模板根据操作方法创建视图,您可以下载 zip 文件夹。运行应用程序,您会发现您的表已在数据库中创建并建立了关系。
注意:下载源代码后,请在 web.config 文件中更改连接字符串并运行应用程序。