zoukankan      html  css  js  c++  java
  • Entity Framework复杂类型属性映射

    零、创建项目必须代码

    public class BaseModel
    {
        public int Id { get; set; }
        public DateTime CreateDateTime { get; set; }
    }
    
    public class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
        public string ZipCode { get; set; }
    }
    
    public class User:BaseModel
    {
      public string Name {get;set;}
      public string Birthdate {get;set;}
      public string IdNumber {get;set;}
      public Address Address {get;set;}
    }
    

    以上代码在ORM中称为组合类,EF会将这两个类映射在一张表中。当Code First发现不能推断出类的主键,并且没有通过Data Annotations或Fluent API注册主键,那么该类型将被自动注册为复杂类型。

    注意:

    1. 复杂类型检测要求该类型不具有引用实体类型的属性,还要求不可引用另一类型的集合属性
    2. 复杂类型的在数据库中映射的列名称为:负载类型类名_属性名

    我们接下来创建 DbContext

    public class EfDbContext : DbContext
    {
        public EfDbContext()
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EfDbContext>());
        }
        public DbSet<User> Users { get; set; }
    }
    

    创建完DbContext类后,我们编写将数据存入数据库的方法:

    
    using (var efDbContext = new EfDbContext())
    {
        var user = new User()
        {
            Birthdate = DateTime.Now,
            CreateDateTime = DateTime.Now,
            Name = "张三",
            IdNumber = "1234567"
        };
        efDbContext.Users.Add(user);
        efDbContext.SaveChanges();
    
    }
    
    

    运行上述代码,会得到如下错误:
    VyO83V.png

    出现上述错误的原因是我们没有初始化 Address 类,其中一个(后面我会讲解另一个解决方法)解决方法是在 new User(){} 内初始化 Address,修正后的代码如下:

    using (var efDbContext = new EfDbContext())
    {
        var user = new User()
        {
            Birthdate = DateTime.Now,
            CreateDateTime = DateTime.Now,
            Name = "张三",
            IdNumber = "1234567",
            Address = new Address()
        };
        efDbContext.Users.Add(user);
        efDbContext.SaveChanges();
    
    }
    

    一、如何正确使用复杂类型

    1. 为避免添加实体报错,应该在实体的构造函数中初始化复杂类型;
    2. 将制度属性添加到复杂类型中时,需进行空值检查;
    3. 尽量显式注册复杂类型。

    现在我们按照上面所述,对我们先前编写的内容进行改造,这三条规则也是解决我们前面所遇到的BUG的另一个方法。

    public class BaseModel
    {
        public int Id { get; set; }
        public DateTime CreateDateTime { get; set; }
    }
    
    public class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
        public string ZipCode { get; set; }
        public bool HasValue
        {
            get
            {
                return (Street != null || ZipCode != null || City != null);
            }
        }
    }
    
    public class User : BaseModel
    {
        public User()
        {
            Address = new Address();
        }
        public string Name { get; set; }
        public DateTime Birthdate { get; set; }
        public string IdNumber { get; set; }
        public Address Address { get; set; }
    }
    
    public class EfDbContext : DbContext
    {
        public EfDbContext()
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EfDbContext>());
        }
    
        public virtual void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.ComplexType<Address>();
        }
    
        public DbSet<User> Users { get; set; }
    }
    
    

    代码改造后我们可以轻松的通过 变更追踪API 来访问数据的原始值和当前值。所谓原始值就是从数据库查询出来的值,当前值就是实体目前的值。入口点是 DbContext的Entry方法,返回对象类型是 DbEntityEntry 。我们看一下访问原始值和当前值得例子:

    using (var efDbContext = new EfDbContext())
    {
        var user = efDbContext.Users.Find(1);
        var oriValue = efDbContext.Entry(user).ComplexProperty(u => u.Address).OriginalValue;
        //将city的值改为北京
        user.Address.City = "北京";
        var curValue = efDbContext.Entry(user).ComplexProperty(u => u.Address).CurrentValue;
    
        Console.WriteLine("原始值:"+oriValue.City+"   当前值:"+curValue.City);
        Console.Read();
    }
    
    

    运行上述代码,将会看到如下的输出:
    V2VUKS.png

    同样,我们也可以通过链式调用,获取复杂了类型的属性或者设置复杂类型的属性:

    var user = efDbContext.Users.Find(1);
    var city = efDbContext.Entry(user).ComplexProperty(u => u.Address).Property(a => a.City).CurrentValue;
    Console.Write(city);
    

    二、复杂类型的限制

    从上面的讲解我们卡一看到,用复杂类型很双,一直用一直爽,但是复杂类型还是有他的限制的:

    1. 不能共享引用:因为没有主键标识,不能被自身实例之外的任何对象引用;
    2. 没有优雅的方式标识空引用:即使查询出的数据为空,EF Code First 依然会初始化复杂类型对象;
    3. 无法延迟加载。
  • 相关阅读:
    gym 101064 G.The Declaration of Independence (主席树)
    hdu 4348 To the moon (主席树 区间更新)
    bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)
    ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)
    hdu 4417 Super Mario (主席树)
    poj 2236 Wireless Network (并查集)
    查看 scala 中的变量数据类型
    彻底搞定Maven
    Spark :【error】System memory 259522560 must be at least 471859200 Error initializing SparkContext.
    ip地址、子网掩码、网关与网卡、DNS的区别及用处
  • 原文地址:https://www.cnblogs.com/gangzhucoll/p/12778207.html
Copyright © 2011-2022 走看看