Learning EntityFramework(5)

复合类型(Complex types)

复合类型(Complex Types)跟Entity类型的区别在于,复合类型(Complex Types)没有Key。复合类型跟踪改变和存储是要依赖宿主类型的。

从代码来看就更直观。

首先,假设我们有一个Person类,这个类包含了SSN,FirstName,LastName和Address的信息。代码如下

public class Person
{
    public int PersonId { get; set; }
    public int SocialSecurityNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

但是根据设计模式或为了能够练习更好的编程习惯,我们会单独抽象出一个Address类,来存储Address的信息。

public class Address
{
    public int AddressId { get; set; }
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}
public class Person
{
    public int PersonId { get; set; }
    public int SocialSecurityNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

如果通过上面的两个类,Code Fist将在数据库中生成两张表,而这又不是我们想要的结果。在数据库层面我们只是想有一张表,而在代码层面,我们希望可以有单独的Address类来存储Address信息。这时候,我们希望把Address定义为一个复合类型,而不是entity类型。

要如何做才能把Address类变成复合类型呢?复合类型和entity类型的区别在于,复合类型没有key。所以,我们只需要把AddressId从Address类中去掉就可以了。

在做插入操作时,出现来另外一个问题,在Person类中的Address如果为NULL时,当调用SaveChanges方法时将会抛出一个DbUpdateException。解决方法也很简单,在Person类的构造函数中,实例化一个Address的实例赋值给Address属性。

另外两个规则应用于复合类型。其一,复合类型只能包含原始(primitive)数据类型;其二,当被其他类使用时,不能是集合类型。换言之,如果Person类中的是一个List<Address>或者另外一个集合类型存在于Address类中,Address将不被视为复合类型。

如果你一定要使用AddressId时,可以通过DataAnnotation,使用[ComplexType]修饰Address类。Fluent API实现方式: modelBuilder.ComplexType<Address>();

让我们来看一个更复杂的复合类型的例子

public class PersonalInfo
{
    public Measurement Weight { get; set; }
    public Measurement Height { get; set; }
    public string DietryRestrictions { get; set; }
}
public class Measurement
{
    public decimal Reading { get; set; }
    public string Units { get; set; }
}

我想让PersonalInfo和Measurement都是复合类型。两个类都没有Key,同样在Person类的构造函数里面也将这两个类型实例化并赋值到对应的属性上。但在运行时依旧会报错。因为PersonalInfo并没有完全满足复合类型的条件——使用原始数据类型。只需要在PersonalInfo类型上面加上[ComplexType]的修饰,就能够使代码正常工作了。
同样的,DataAnnotation和FluentAPI都可以对复合类型里面的属性进行配置。

原文地址:https://www.cnblogs.com/OliverZh/p/ef5.html