zoukankan      html  css  js  c++  java
  • 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类,因为它遵循复杂类的规则。

     --=本文源码=--

    作者:Rising Sun
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    某个牛人做WINDOWS系统文件详解
    常用ASP脚本程序集锦
    LINUX基础:文件安全与权限
    proftpd+mysql+quota
    apache2.0.49tomcat5.0.19jk2建立virtualHost
    URL Redirection(转) Anny
    顶级域名后缀列表(转) Anny
    \u4E00\u9FA5意义 Anny
    How to POST Form Data Using Ruby(转) Anny
    How to get rid of 'Enter password to unlock your login keyring' in Ubuntu(转) Anny
  • 原文地址:https://www.cnblogs.com/lxblog/p/3090479.html
Copyright © 2011-2022 走看看