Entity Framework Code First 方法,使用数据注解和 Fluent API






4.82/5 (13投票s)
Entity Framework 的各种方法,以及 Code First 方法的示例
引言
我计划在后续一系列文章中介绍 Entity Framework 的一些重要功能。我希望它能帮助从新手到经验丰富的 .NET 开发人员。
我假设您已经熟悉“Entity Framework”这个术语,并且想了解更多关于它的信息。那么您来对地方了。是的,Entity Framework 是微软的 ORM(对象关系映射器)。我之所以说是微软的产品,是因为有许多其他厂商也有类似的产品。NHibernate 就是其中之一,它提供了类似的功能。让我们来理解“对象关系映射器”这个术语。在这里,对象就是我们的类,而关系则代表存储在数据库中的表。在过去,开发人员会手动编写代码来获取数据,并将数据转换为领域对象,然后跨层传递对象。然后行业开始考虑让开发人员的生活更轻松。他们开始通过某些框架来自动化映射过程,这些框架能够从数据库自动创建类,或者能够将表复制为类。所以,简而言之,这就是使用 Entity Framework 的目的,它可以自动生成模型代码,负责 SQL 查询,让开发人员的生活更轻松。即使您对数据库部分不太熟悉,Entity Framework 也会为您处理。让我们进入下一个讨论,我们如何在应用程序中使用 Entity Framework?在应用程序中实现 Entity Framework 有三种方法。我们将讨论这些方法,以便更好地理解本系列文章的后续内容。
代码优先方法
顾名思义,在这种方法中,我们首先编写代码来生成数据库,然后有一天,我们将运行这些代码在数据库服务器中看到数据库。以下是我们可以实现 Code First 方法的几个可能场景。
- 您是一个硬核开发者,总是喜欢与代码玩耍,那么 Code First 方法非常适合您。
- 如果您想在不了解太多 SQL 和 DBA 的情况下完全控制数据库设计。
- 如果应用程序是全新的,并且没有现有的数据库。
所以,如果出现以上任何一种情况,您都可以放心地使用 Code First 方法。老实说,这种方法是三种方法中最受欢迎的一种,根据我个人的经验,我见过许多全新项目都采用了这种方法。
数据库优先 (Database First)
这是继 Code First 方法之后的下一个流行方法。Database First 方法最适合数据库已创建的情况,但这里还有一些其他可能性。
- 当数据库已存在时,您只需要开发应用程序。
- 当数据库结构非常复杂,需要 DBA 专业人员参与时。
- 当您有兴趣同时处理应用程序的编码和数据库部分时。
- 如果您想在 POCO 实体中添加额外功能,您必须修改 T4 模板或使用部分类。
- 在这种方法中,手动更改数据库非常容易,因为它不直接依赖于代码。更改数据库,更新模型,工作顺利。
所以,这些是 Database First 方法适用的场景。
模型优先 (Model First)
我的个人经验表明,这种方法不如 Code First 和 Database First 流行的原因可能是,开发人员不想扮演设计者的角色。同样,以下是人们应该选择 Model First 方法的几个可能场景。
- 当您想先创建数据模型并与非技术人员共享时。通过查看代码和表,非技术人员可能不理解,但她可能会理解实体的多彩表示。
- 当您的应用程序是全新的,并且您不介意大量的自动生成代码,并且您知道在出现问题时在哪里进行调整。
无论如何,优点是,一旦设计了模型,它将同时创建您的类和数据库。好的,我们已经理解了 Entity Framework 的各种工作流程以及它们适用的场景。现在,在这篇文章中,我们将通过示例讨论 Code First 方法,并在连续的文章中深入探讨 Entity Framework。
需要指出的是,Code First 方法有两种方式可以实现
- 数据注解
- Fluent API
两者都流行且有用,但选择权在您。无论如何,我将在这里展示两种方式的 Code First 方法。所以,创建一个全新的应用程序,我选择了控制台应用程序进行演示,您可以自由选择任何其他类型。
使用数据注解的 Code First 方法
创建一个 `.cs` 文件并命名为 `person.cs`,然后将以下代码粘贴进去。由于这是数据注解方法,请不要忘记添加 `System.ComponentModel.DataAnnotation` 命名空间。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public class Person
{
[Key]
public int Id{get;set;}
[Required]
public string name { get; set; }
[Required]
public string surname { get; set; }
}
public class Address
{
[Key]
public int personAdressId { get; set; }
public string address { get; set; }
[MaxLength(6)]
public string pin { get; set; }
[ForeignKey("Person")]
public int PersonId { get; set; }
//Navigation property
public virtual Person Person { get; set; }
}
public class personContext : DbContext
{
public personContext()
: base("DBConnectionString")
{
//If model change, It will re-create new database.
Database.SetInitializer<personContext>(new DropCreateDatabaseIfModelChanges<personContext>());
}
public DbSet<Person> person { get; set; }
public DbSet<Address> Address { get; set; }
}
}
如果您熟悉 MVC 中的数据注解,那么我相信您对这些属性很熟悉。`Key` 属性表示表的主键(我们稍后运行此脚本来创建表)。`Person` 和 `Address` 类非常容易理解。请记住,我们在 `Address` 类中设置了外键属性,它将指向 `Person` 类的主键。现在,让我们讨论上下文的创建部分。请看 `PersonContext` 类的定义。我们从 `DbContext` 类继承了它,在构造函数中,我们传递了“DBConnectionString”,我们将在 `web.config` 文件中稍后定义它。在构造函数中,我们指定要从头开始创建数据库。如果我的模型发生更改,这里是代码:`Database.SetInitializer
现在,我们将在应用程序的 `web.config` 文件中指定连接字符串。
<connectionStrings>
<add name="DBConnectionString"
connectionString="Data Source=SOURAV-PC;Initial Catalog=personDB;Integrated Security=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
连接字符串非常简单。我没有包含用户名和密码,因为我希望使用 Windows 身份验证。如果需要,您可以提供数据库凭据。请注意,我提供的数据库名称是“personDB”,这意味着当我的代码创建数据库时,我期望的数据库名称就是这个。好了,我们已经完成了必要的设置。现在我们将运行代码来填充数据库。如果您像我一样使用控制台应用程序,只需修改 `Main()` 函数如下:
public static void Main(string[] args)
{
using (var ctx = new personContext())
{
ctx.Database.Create();
}
}
现在,让我们运行应用程序,等待奇迹发生。一旦它无异常地运行(希望如此),请检查您的数据库。这是我的:
您将看到上述数据库结构,其中会创建两个表并关联所有键。所以,这就是使用 Entity Framework 的 Code First 方法通过数据注解创建数据库的方法。
现在,我们将使用 Fluent API 实现相同的模型来创建数据库。请看 `person.cs` 文件中修改后的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public class Person
{
public int Id{get;set;}
public string name { get; set; }
public string surname { get; set; }
}
public class Address
{
public int personAdressId { get; set; }
public string address { get; set; }
public string pin { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
public class personContext : DbContext
{
public personContext()
: base("DBConnectionString")
{
//If model change, It will re-create new database.
Database.SetInitializer<personContext>(new DropCreateDatabaseIfModelChanges<personContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set primary key to Person table
modelBuilder.Entity<Person>().HasKey(m => m.Id).Property(m => m.Id).IsRequired();
//name fleld is required
modelBuilder.Entity<Person>().Property(p => p.name).IsRequired();
//surname is required
modelBuilder.Entity<Person>().Property(p => p.surname).IsRequired();
//set primary key to Address table
modelBuilder.Entity<Address>().HasKey(m => m.personAdressId);
//set max length property to 6
modelBuilder.Entity<Address>().Property(m => m.pin).HasMaxLength(6);
//Set foreign key property
modelBuilder.Entity<Address>().HasRequired(t => t.Person)
.WithMany().HasForeignKey(t => t.PersonId);
}
public DbSet<Person> person { get; set; }
public DbSet<Address> Address { get; set; }
}
}
`Main()` 函数中的代码将保持不变,一旦我们运行应用程序,我们将获得相同的数据库结构。
总结
由于这是本系列的第一篇文章,我讨论了一些基本概念和示例。在未来的文章中,我们将重点关注 Code First 方法的各种主题。