今天主要介绍EF Code First中一个高级部分: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>();

以下为一个测试的方法,看他是怎么样生成到数据库的表的:

[TestMethod]

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

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

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

可以看到生成的对应表结构如下:

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

我们也可以改变这种方式:
public class AddressComplexTypeConfiguration:ComplexTypeConfiguration<Address>    {
        public AddressComplexTypeConfiguration()
        {
            Property(a => a.Country).HasColumnName("Country").HasMaxLength();
            Property(a => a.Province).HasColumnName("Province").HasMaxLength();
            Property(a => a.City).HasColumnName("City").HasMaxLength();
            Property(a => a.StreetAddress).HasColumnName("StreetAddress").HasMaxLength();
            Property(a => a.ZipCode).HasColumnName("ZipCode").HasMaxLength();
        }
    }

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

总结:本章主要还是讲的是Fluent API的配置映射,如何生成对应的数据库的表结构。

Code First05--CodeFirst中值对象的更多相关文章

  1. 关于项目中值对象Identifier的设计-领域驱动

    到现在为止做了不项目,发现每个实体都会有个相应的值对象. 先简单说一下值对象和实体之间的区别: (以下内容来着<领域驱动设计>一书) 当一个小孩画画的时候,他注意的是画笔的颜色和笔尖的粗细 ...

  2. EFCore:关于DDD中值对象(Owns)无法更新数值

    最近使用DDD+EFCore时,使用EFCore提供的OwnsOne或者OwnsMany关联值对象保存数据,没想到遇到一个很奇怪的问题:值对象中的值竟然无法被EFCore保存!也没有抛出任何异常!我瞬 ...

  3. DDD 领域驱动设计-Value Object(值对象)如何使用 EF 进行正确映射

    写在前面 首先,这篇博文是用博客园新发布的 MarkDown编辑器 编写的,这也是我第一次使用,语法也不是很熟悉,但我觉得应该会很爽,博文后面再记录下用过的感受,这边就不多说. 阅读目录: 上一篇回顾 ...

  4. Value Object(值对象)如何使用 EF 进行正确映射

    DDD 领域驱动设计-Value Object(值对象)如何使用 EF 进行正确映射 写在前面 首先,这篇博文是用博客园新发布的 MarkDown编辑器 编写的,这也是我第一次使用,语法也不是很熟悉, ...

  5. [原创]java WEB学习笔记59:Struts2学习之路---OGNL,值栈,读取对象栈中的对象的属性,读取 Context Map 里的对象的属性,调用字段和方法,数组,list,map

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  6. DDD Code First 迁移数据实现EF CORE的软删除,值对象迁移配置

    感谢Jeffcky大佬的博客: EntityFramework Core 2.0全局过滤 (HasQueryFilter) https://www.cnblogs.com/CreateMyself/p ...

  7. DDD实战12 值对象不创建表,而是直接作为实体中的字段

    这里的值对象如下风格: namespace Order.Domain.PocoModels { //订单地址 //虽然是值对象 但是不继承ValueObject //因为继承ValueObject会有 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (44) ------ 第八章 POCO之POCO中使用值对象和对象变更通知

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-4  POCO中使用值对象(Complex Type--也叫复合类型)属性 问题 ...

  9. DDD 领域驱动设计-“臆想”中的实体和值对象

    其他博文: DDD 领域驱动设计-三个问题思考实体和值对象 DDD 领域驱动设计-三个问题思考实体和值对象(续) 以下内容属于博主"臆想",如有不当,请别当真. 扯淡开始: 诺兰的 ...

随机推荐

  1. Ubuntu学习总结-02 Ubuntu下的FTP服务的安装和设置

    一 安装vsftpd 在安装前vsftpd,先更新apt-get下载的数据源输入如下命令: sudo apt-get update 然后安装vsftpd sudo apt-get install vs ...

  2. 利用 Django REST framework 编写 RESTful API

    利用 Django REST framework 编写 RESTful API Updateat 2015/12/3: 增加 filter 最近在玩 Django,不得不说 rest_framewor ...

  3. 开发板ping不通主机和虚拟机的看过来(转载)!

    前几天在做uboot下用tftp下载文件到开发板的实验时,为了能解决开发板ping不通主机和虚拟机的问题,可谓绞尽脑汁,正所谓久病成医,虽然为了这一小问题废了我那么长时间,但我在解决问题的同时也学到了 ...

  4. Python2.7安装(win7)

    Python可在官方网站直接下,或者百度一下Python2.7下载,这里推荐使用2.7而不是3.3,比较适合初学者 工具/原料 win7系统 python2.7安装包 方法/步骤 1.从官网下载最新的 ...

  5. PyQ1_介绍

    PyQt是一个创建GUI应用程序的工具包.它是Python编程语言和Qt库的成功融合.Qt库是目前最强大的库之一.PyQt是由Phil Thompson 开发.   PyQt实现了一个Python模块 ...

  6. C# “配置系统未能初始化” 异常解决

    使用App.config配置参数,读取参数出现错误 “System.Configuration.ConfigurationErrorsException”类型的未经处理的异常在 System.Conf ...

  7. (转)Java中的String为什么是不可变的

    转自:http://www.importnew.com/7440.html String是所有语言中最常用的一个类.我们知道在Java中,String是不可变的.final的.Java在运行时也保存了 ...

  8. 解惑好文:移动端H5页面高清多屏适配方案 (转)

    转自:http://mobile.51cto.com/web-484304.htm https://github.com/amfe/lib-flexible/blob/master/src/makeg ...

  9. ecshop 调用收货地址

    html {insert_scripts files='region.js,utils.js'} <script type="text/javascript"> reg ...

  10. int main(int argc, char * argv[]) 里的异常处理

    #import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { ...