Entity Framwork CodeFirst 学习笔记三:使用复杂类型

上一篇,主要学习了一些CodeFirst 中修改默认规约的基本配置。在文章最后,出现了个新的名词:复杂类型。什么是复杂类型呢?

书中说道:“复杂类型也可视作值类型(?)可以作为附加属性添加到其他类。复杂类型与实体类型的区别在于复杂类型没有其自己的键。它是依赖于其"宿主"类型跟踪变化 和持久化。一个没有Key属性的类型,并且作为属性映射到一个或多个类型中,Code First就会将其视作为复杂类型。Code First将预设复杂类型的属性出现在宿主类型映射到数据库的表中。”

说简单一点就是,项目中有个类A,这个A,会被其他类引用到比如:实体类B 和 实体类C,但是建立数据库的时候,我们不想为这个分割类A建立表,而是把A类中的属性等建立到 B 和 C 映射的表中,这时候,我们管 A 叫做复杂类型。

 来看一下书中的解释和例子:

比如有如下类:

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类作为分割类,不仅可以简化Person类,而且还可以提高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; } }

 如果这样做的话,CodeFirst 使用默认规则,肯定会产生一个单独的表:Addresses。而我们希望的是 Address中的属性成为表Person中的字段。这时候,我们需要告诉EF,Address类是个复杂类型,就能解决我们现在遇到的问题。

一、使用默认规则:

使用负责类型默认规则,我们需要遵循三个原则:
1、复杂类型无Key属性
2、复杂类型只包含原始属性
3、用作其他类的属性时,属性必须是一个单一实例,不能用于集合类型

上例代码中,我们需要注释掉 :

//public int AddressId { get; set; }

 然后在Person中增加构造函数: 

public Person()
{
    Address = new Address();
}

 这样,运行程序的话,Address类就会被认作是 复杂类型了。

二、DataAnnotation 方式:

DataAnnotation 更加简单 只需要在复杂类型的类上增加属性标签[ComplexType]

[ComplexType]
public class Address
{        
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

 三、FluntAPI 方式:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.ComplexType<Address>();
    base.OnModelCreating(modelBuilder);
}

 生成的表结构如下图:

我们会发现,生成的表结构的字段名称和类型均是EF默认的,我们当然也可以对其进行配置,我们来用FluntAPI进行配置一下:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
    //设置Person 类的表名为 t_People
    modelBuilder.Entity<Person>().ToTable("t_People");

    //设置 PersonId 为主键且自动增长
    modelBuilder.Entity<Person>().HasKey(p => p.PersonId)
                                 .Property(p => p.PersonId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    //设置Firstname 和 Lastname 的长度为 20
    modelBuilder.Entity<Person>().Property(p => p.FirstName).HasMaxLength(20);
    modelBuilder.Entity<Person>().Property(p => p.LastName).HasMaxLength(20);

    //设置Address 为复杂类型吗,并设置字段名称及长度
    modelBuilder.ComplexType<Address>().Property(a => a.City).HasColumnName("City").HasMaxLength(20);
    modelBuilder.ComplexType<Address>().Property(a => a.State).HasColumnName("State").HasMaxLength(20);
    modelBuilder.ComplexType<Address>().Property(a => a.StreetAddress).HasColumnName("Steet").HasMaxLength(30);
    modelBuilder.ComplexType<Address>().Property(a => a.ZipCode).HasColumnName("ZipCode").HasMaxLength(10);

    base.OnModelCreating(modelBuilder);
 }

 生成的表结构如下图:

四、复杂类型的嵌套

上面已经指出,复杂类型应该只包括原始属性。但如果在复杂类型中继续引用一个类会产生什么样的结果呢?继续书中的例子:

再创建了两个新类,PersonalInfo 类 和 Measuremet 类,PersonalInfo 包含有两个Measurement 属性。

注意两个类都没有标识属性。我们的意图是两个类都成为复杂类型。PersonalInfo复杂类型使用Measurment复杂类型,这就是所谓的嵌套复杂类型。

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; }
}

 向Person类中添加新的PersonInfo属性:

public PersonalInfo Info { get; set; }

 修改Person类的构造函数:

public Person()
{
   Address = new Address();
   Info = new PersonalInfo
   {
    Weight = new Measurement(),
    Height = new Measurement()
   };
} 

 然后,我们去掉先前配置的那些 DataAnnotation 和 FluntAPI,采用默认的配置方式,我们运行一下程序,会出现以下错误:

实体类"PersonInfo"没有定义键。请为此实体类定义键。

Code First 并没有将PersonalInfo识虽为复杂类型。原因是打破了规则:复杂类型必须只包含原生类型。在PersonalInfo类中有两个Measurement类型的属性。由于这是非原生类型,规则不能将PersonalInfo作为复杂类型

解决方法:对PersonalInfo 类 配置 [ComplexType] 属性,就能够将属性建立到表中,不需要配置配置Measurement类,因为它遵循复杂类的规则。

 --=本文源码=--

转载于:https://www.cnblogs.com/lxblog/archive/2013/05/21/3090479.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值