为什么要使用Code First:
近年来,随着domain driven design的推广,以前那种先建好数据库,然后再编写代码的方式受到了越来越多的质疑。因为使用这种开发方式很难适应领域内业务逻辑的改变,它需要当每次领域发生改变的时候,先改变数据库,然后再改变业务逻辑和实体的代码,开发周期比较长,而且不利于单元测试。所以随着domain driven design一同推广的还有Persistence Ignorance 原则和POCO(Plain Old CLR Object). Persistence Ignorance principle说白了就是把domain driven design中的实体,值对象,服务与数据存储功能完全隔离,使他们不掺杂任何与数据存储相关的代码。在随后的实例中,大家可以看到如何通过Code First实现这些。
所谓的Code First就是先写业务逻辑部分的代码,实现domain driven design当中的实体,值类型和服务,然后通过Code First默认的习惯或者配置把他们映射到数据库中去。这样做一方面可以让我们先把全部的精力投放到业务逻辑的设计和实现中,并且可以在实现业务逻辑后,使用一些Mock工具单独对业务逻辑代码进行测试。另一方面,当我们对业务逻辑进行proof-of-concept时,可以通过几个简单的界面就可以做出prototype去给客户演示了。通过使用Code First方式,使我们能更快的对应业务逻辑的改变和原型搭建。所以Code First非常适用于使用domain driven design的新建项目使用。
关于使用Code First的好处以及使用它的场合,相信通过前面的介绍大家已经清楚了,还是让我们回到代码,通过最简单的一个实例程序看看Code First是怎么按照他的约定来实现数据库的映射的。
Code First遵循的是Convention over Configuration的原则,也就是说如果你对领域中的各类对象的映射没有进行配置的话, Code First就会按照他的默认习惯进行领域对象与数据库的映射。
我在本系类的日记中使用的实例是给公司内部新员工培训使用的一个简单的订单管理系统,包含客户,订单,订单条目,产品,产品目录等实体和值对象。
让我们先考虑最简单的产品目录吧,假设我们的产品目录是一个值对象包含以下属性:
public class ProductCatalog
{
public int ProductCatalogId { get; set; }
public string CatalogName { get; set; }
public string Manufactory { get; set; }
public decimal ListPrice { get; set; }
public decimal NetPrice { get; set; }
}
怎么才能够让Entity Framework认识你定义的值对象并且把它映射成数据库中的表呢?你需要定义一个继承DbContext类的子类,然后在这个子类中添加一个泛型DbSet的属性,类型参数就是你自定义的ProductCatalog类。
public class OrderSystemContext:DbContext
{
public DbSet<ProductCatalog> ProductCatalogs { get; set; }
}
然后你可以使用你定义的OrderSystemContext类进行数据操作了。
var context = new OrderSystemContext();
var catalogs = context.Catalogs.Where(c => c.ProductCatalogId == 1);
现在就让我们来介绍一下Entity Framework Code First中的映射习惯吧。
-
数据库映射:Code First 默认会在本地的SQL
Expression数据库中建立一个和DbContext的子类的全名相同的数据库,全名指的是命名空间加上类名。当然后边会介绍怎么进行配置。 -
表映射:Code First 默认会按照类型名复数建立数据表,比如说ProductCatalog类对应的表名就叫ProductCatalogs.后边会介绍如何改变默认的表名。
-
列映射:Code First
默认会按照类中的属性名建立column,它还有默认的数据类型映射习惯,int会映射为interger,string会映射为nvarchar(max),decimal会映射为decimal(18,2)。后边会介绍如何更改column的名称,类型以及其他特性。 -
主键映射:Code First
默认会在类的属性中需找名字为Id或类型名称+Id的int类型的属性作为主键,并且是自增字段。这些也是可以改的。
这个程序执行完之后就会在默认的SQL Expression中建立一个名为xxx.OrderSystemContext的类,并且建立一个名字为ProductCatalogs的表,表的具体结构如下:
当然,我们既然使用domain driven design就完全应该按照我们领域中的实际业务情况设计我们的类,这样就不可能使我们的类完全遵守Code First的习惯,接下来的学习日记将主要具体介绍如何通过Code First的配置功能将我们领域中各种各样的类和类之间的关系映射到数据库中。