刘凯的博客

导航

Entity Framework Code First 学习日记(3)

我在上一篇日记的最后已经预告了,我这次将给大家介绍一下如何将Fluent API的配置组织的更好,更利于维护,但是一位“特别”同志迫不及待地揭晓了谜底,那么就让我们来看一下Fluent API的另一种使用方式吧。

我们项目中的domain中一般都有很多的类,如果我们把所有类的代码都写在DbContext子类的OnModelCreating重载方法中,那么这个方法将会非常庞大,并且各个类的配置都混杂在一起,非常不利于项目的后期维护。所以我们就需要更好地组织Fluent API的数据映射配置。

从上一篇日记我们知道modelBuilder的Entity<>泛型方法的返回值是EntityTypeConfiguration<>泛型类。我们可以定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,我们在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射。

public class CustomerEntityConfiguration:EntityTypeConfiguration<Customer>
    {
        public CustomerEntityConfiguration()
        {
            HasKey(c => c.IDCardNumber).Property(c => c.IDCardNumber).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            this.Property(c => c.IDCardNumber).HasMaxLength(20);
            this.Property(c => c.CustomerName).IsRequired().HasMaxLength(50);
            this.Property(c => c.Gender).IsRequired().HasMaxLength(1);
            this.Property(c => c.PhoneNumber).HasMaxLength(20);
        }
    }

昨天我们已经介绍了怎样去改变Code First默认的数据库映射。但是当我们通过Fluent API改变数据库映射时,Code First会如何处理与新的数据库映射不匹配的数据库呢?

通过Code First提供的Database类的SetInitializer方法设定Code First如何根据Fluent API数据库映射配置初始化数据库。

每次AppDomain加载的时候会执行SetInitializer指定的初始化方法。

SetInitializer方法的参数可以使以下三个泛型类的对象:

CreateDatabaseIfNotExists<>:只有在没有数据库的时候才会根据数据库连接配置创建新的数据库。这种配置主要用于production环境,因为你不可能把你现在使用的数据库删除掉,那样会损失重要的数据。你需要让你的实施人员拿着与Fluent API配置对应的数据库脚本去更新数据库。

 

DropCreateDatabaseIfModelChanges<>:只要Fluent API配置的数据库映射发生变化或者domain中的model发生变化了,就把以前的数据库删除掉,根据新的配置重新建立数据库。这种方式比较适合开发数据库,可以减少开发人员的工作量。

 

DropCreateDatabaseAlways<>:不管数据库映射或者model是否发生变化,每次都重新删除并根据配置重建数据库。这种方式可以适用于一些特殊情况的测试,比如说当每次测试结束之后把所有的测试数据都删除掉,并且在测试开始前插入一些基础数据。

一般Database.SetInitializer方法都是在应用程序的入口,比如Global.ascx.cs,Main方法等地方调用的。

但是通过代码调用设置数据库的初始化方式并不是很方便,因为每种初始化方式都应用于不同的场合,当我们从开发环境变化到production环境时,肯定会使用不同的初始化方式,比如说从DropCreateDatabaseIfModelChanges变为CreateDatabaseIfNotExists。如果每次变化都要重新改代码,重新编译的话,太不方便了。

我们可以通过配置指定数据库初始化的方式,这样就可以更灵活的改变我们的初始化方式:

<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="DatabaseInitializerForType OrderSystemContext"
value="System.Data.Entity.DropCreateDatabaseIfModelChanges[[OrderSystemContext]], EntityFramework" />

</appSettings>
</configuration>

我们还以自定义数据库初始化类,通过自定的初始化类,还可以将一些基础数据在创建数据库之后插入到数据库中去。

假设我们在测试环境中测试对Product类的相关操作,我们需要一些ProductCatalog的基础数据,因为Product中有一个Productcatalog的引用。我们可以定义一个自己的数据库初始化类,继承DropCreateDatabaseAlways,让Code First每次在执行测试之前都删除掉原来的数据库并且插入一些ProductCatalog的测试数据。

 

public class DropCreateOrderDatabaseWithSeedValueAlways : DropCreateDatabaseAlways<OrderSystemContext>
   {
       protected override void Seed(OrderSystemContext context)
       {
           context.ProductCatalogs.Add(new ProductCatalog { CatalogName = "DELL E6400", Manufactory = "DELL", ListPrice = 5600, NetPrice = 4300 });
           context.ProductCatalogs.Add(new ProductCatalog { CatalogName = "DELL E6410", Manufactory = "DELL", ListPrice = 6500, NetPrice = 5100 });
           context.ProductCatalogs.Add(new ProductCatalog { CatalogName = "DELL E6420", Manufactory = "DELL", ListPrice = 7000, NetPrice = 5400 });
       }
   }

 

我们在测试类的测试初始化方法中就可以指定Code First使用我们自定义的初始化类进行数据库的初始化:

Database.SetInitializer(new DropCreateOrderDatabaseWithSeedValueAlways());

然后我们就可以使用初始化时插入的基础数据进行我们的测试了:

[TestMethod]
        public void CanAddProduct()
        {
            OrderSystemContext unitOfWork = new OrderSystemContext();
            ProductRepository repository = new ProductRepository(unitOfWork);
            ProductCatalog catalog = repository.SearchProductCatalog(c => c.CatalogName == "DELL E6400", 1, 10)[0];
            Product product = new Product { Catalog = catalog, CreateDate = DateTime.Parse("2010-2-10"), ExpireDate = DateTime.Parse("2012-2-10") };
            repository.AddNewProduct(product);
            unitOfWork.CommitChanges();
        }

 

我们打开SQL Server就可以发现基础的测试数据了:

image

 

PS:接下来的日记将涉及DbContext的一些配置,有兴趣剧透的同学可以继续猜测一下,谜题明天揭晓。

posted on 2013-01-10 21:57  刘凯  阅读(5722)  评论(12编辑  收藏  举报