zoukankan      html  css  js  c++  java
  • Entity Framework Code First 学习日记(5)

    我今天要介绍怎样使用Entity Framework Code First的高级配置功能来处理domain driven design 中的另一种重要组成部分:Value Object,中文翻译过来叫做值对象。

    所谓的值对象就是一些没有生命周期,也没有业务逻辑上唯一标识符的类。哪些类是Entity,哪些类是Value Object不是固定的,取决于具体的业务逻辑。比如说Customer这个类,如果在CRM系统当中,它是最重要的信息,我们需要跟踪它的状态,管理它的生命周期。但是在其他系统中,客户信息可能只代表一个名字和一些其他的属性。

    值对象应该是不可修改的,因为它只代表一些临时的属性集合,并没有生命周期需要维护。

    我们的订单管理系统中有一个Customer类。在我们以前的示例中,Customer类的Address属性是一个字符串。现在我们的业务逻辑发生了改变,需要把地址信息分类显示和保存,把地址信息细分为国家,省,城市,街道及门牌号,还有邮政编码。在我们的业务中,地址信息仅仅是一些属性的集合,不需要跟踪它的生命周期,也不存在业务中的唯一标识符。所以我们把它定义为一个Value Object:

    public class Address
        {
            public string Country { get; set; }
            public string Province { get; set; }
            public string City { get; set; }
            public string StreetAddress { get; set; }
            public string ZipCode { get; set; }
        }

    想要让Entity Framework Code First默认地识别出值对象,我们的类必须具备三个条件:

    1.值对象类不能有主键。

    2.值对象类只能包含.net基础类型的属性。

    3.使用值对象的类,只能包含值对象的一个实例,不能使用值对象的集合。

    然后我们需要改变我们的Customer类,使用Address值对象来替代以前的字符串。

    public class Customer
        {
            public string IDCardNumber { get; set; }
            public string CustomerName { get; set; }
            public string Gender { get; set; }
            public Address Address { get; set; }
            public string PhoneNumber { get; set; }
        }

     

    如果值对象不满足三个默认的值对象识别条件,我们就需要在我们自定义的DbContext类的OnModelCreating方法中声明Address是一个值对象。

    modelBuilder.ComplexType<Address>();

    我们在我们的单元测试中添加一个新的测试方法来使用Address值对象。

    [TestMethod]
            public void CanAddNewCustomerWithAddress()
            {
                OrderSystemContext unitOfWork = new OrderSystemContext();
                CustomerRepository repository = new CustomerRepository(unitOfWork);
                Customer newCustomer = new Customer() { IDCardNumber = "120104198106072518", CustomerName = "Alex", Gender = "M", PhoneNumber = "test" }
                Address customerAddress = new Address { Country = "China", Province = "Tianjin", City = "Tianjin", StreetAddress = "Crown Plaza", ZipCode = "300308" };
                newCustomer.Address = customerAddress;
                repository.AddNewCustomer(newCustomer);
                unitOfWork.CommitChanges();
            }

    我们使用可插入基础数据的DropCreateOrderDatabaseWithSeedValueAlways自定义数据库初始化类,每次执行测试方法之前都重新建立数据库。

    [TestInitialize]
           public void InitializeCustomerRepositoryTest()
           {
               Database.SetInitializer(new DropCreateOrderDatabaseWithSeedValueAlways());
           }

    测试程序执行之后的Customer表结构如下:

    image

    我们可以看到Entity Framework Code First默认会把Address值对象的属性作为Customers表的列。列的名字默认是值对象类的名字+“_”+值对象属性的名字。

    我们可以改变Entity Framework Code First默认的处理方式。

    我们可以定义一个继承自ComplexTypeConfiguration<Address>的类,在这个类中重载Code First对值对象的默认处理方式。我们可以改变那些列的名字和它们的数据类型和长度。

    public class AddressComplexTypeConfiguration:ComplexTypeConfiguration<Address>
        {
            public AddressComplexTypeConfiguration()
            {
                Property(a => a.Country).HasColumnName("Country").HasMaxLength(100);
                Property(a => a.Province).HasColumnName("Province").HasMaxLength(100);
                Property(a => a.City).HasColumnName("City").HasMaxLength(100);
                Property(a => a.StreetAddress).HasColumnName("StreetAddress").HasMaxLength(500);
                Property(a => a.ZipCode).HasColumnName("ZipCode").HasMaxLength(6);
            }
        }

    我们通过HasColumnName这个方法,可以改变属性对应的列的名字。Entity Framework Code First默认会使用类中属性的名字作为列的名字。

    重新执行我们的测试方法,Customer表的结构如下:

    image

    明天我会介绍与数据表相关的配置。虽然说我写这个系列的文章主要是为了巩固我对Entity Framework Code First的学习和使用经验,但是如果大家觉得我的哪些表达方式不太好,或者太罗嗦,希望大家提意见,我会尽量改正,谢谢

    王胖子2012的意见。

  • 相关阅读:
    一个简单的链表结构 分类: C/C++ 数据结构与算法 2015-06-14 16:39 129人阅读 评论(1) 收藏
    整数与浮点数的二进制表示方式 分类: C/C++ 2015-06-13 15:45 54人阅读 评论(0) 收藏
    对string的一些扩展函数 分类: C/C++ 2015-06-12 15:43 170人阅读 评论(1) 收藏
    SQL常用操作 2015-06-12 12:43 20人阅读 评论(0) 收藏
    Google C++编程风格 2015-06-11 11:25 36人阅读 评论(0) 收藏
    C++头文件编译问题 分类: C/C++ 2015-06-10 15:48 32人阅读 评论(0) 收藏
    服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
    解决time_wait过多的问题
    Gdb调试多进程程序
    linux查看硬件配置命令
  • 原文地址:https://www.cnblogs.com/lk8167/p/2861919.html
Copyright © 2011-2022 走看看