资讯专栏INFORMATION COLUMN

Entity Framework复杂类型属性映射

timger / 737人阅读

摘要:零创建项目必须代码以上代码在中称为组合类,会将这两个类映射在一张表中。当发现不能推断出类的主键,并且没有通过或注册主键,那么该类型将被自动注册为复杂类型。入口点是的方法,返回对象类型是。

零、创建项目必须代码
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注册主键,那么该类型将被自动注册为复杂类型。

注意:

复杂类型检测要求该类型不具有引用实体类型的属性,还要求不可引用另一类型的集合属性

复杂类型的在数据库中映射的列名称为:负载类型类名_属性名

我们接下来创建 DbContext

public class EfDbContext : DbContext
{
    public EfDbContext()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges());
    }
    public DbSet 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();

}

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

出现上述错误的原因是我们没有初始化 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();

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

为避免添加实体报错,应该在实体的构造函数中初始化复杂类型;

将制度属性添加到复杂类型中时,需进行空值检查;

尽量显式注册复杂类型。

现在我们按照上面所述,对我们先前编写的内容进行改造,这三条规则也是解决我们前面所遇到的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());
    }

    public virtual void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.ComplexType
(); } public DbSet 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();
}

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

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

var user = efDbContext.Users.Find(1);
var city = efDbContext.Entry(user).ComplexProperty(u => u.Address).Property(a => a.City).CurrentValue;
Console.Write(city);
二、复杂类型的限制

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

不能共享引用:因为没有主键标识,不能被自身实例之外的任何对象引用;

没有优雅的方式标识空引用:即使查询出的数据为空,EF Code First 依然会初始化复杂类型对象;

无法延迟加载。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/61655.html

相关文章

  • Entity Framework复杂类型属性映射

    摘要:零创建项目必须代码以上代码在中称为组合类,会将这两个类映射在一张表中。当发现不能推断出类的主键,并且没有通过或注册主键,那么该类型将被自动注册为复杂类型。入口点是的方法,返回对象类型是。 零、创建项目必须代码 public class BaseModel { public int Id { get; set; } public DateTime CreateDateTi...

    Drinkey 评论0 收藏0
  • Entity Framework 约定

    摘要:约定,类似于接口,是一个规范和规则,使用定义约定来配置模型和规则。在这里约定只是记本规则,我们可以通过或者来进一步配置模型。约定的形式有如下几种类型发现约定主键约定关系约定复杂类型约定自定义约定零类型发现约定在中。 约定,类似于接口,是一个规范和规则,使用Code First 定义约定来配置模型和规则。在这里约定只是记本规则,我们可以通过Data Annotaion或者Fluent A...

    PAMPANG 评论0 收藏0
  • Entity Framework 约定

    摘要:约定,类似于接口,是一个规范和规则,使用定义约定来配置模型和规则。在这里约定只是记本规则,我们可以通过或者来进一步配置模型。约定的形式有如下几种类型发现约定主键约定关系约定复杂类型约定自定义约定零类型发现约定在中。 约定,类似于接口,是一个规范和规则,使用Code First 定义约定来配置模型和规则。在这里约定只是记本规则,我们可以通过Data Annotaion或者Fluent A...

    王岩威 评论0 收藏0
  • Entity Framework 继承映射

    摘要:一是常用的策略,通过外键来表示继承,父类和子类分别位于不同的表中,子类表包含自身属性列和父类表的外键,并将父表的外键作为子类表的主键。与父类的多态关联将被表示为引用父类表的外键。 继承是面向对象开发时经常用到的,但是SQL Server 数据库不具备继承,那么怎么办能?我们可以利用如下三种方法: TPH(Table per Hierachy):对SQL架构进行非规范化来表示多态,使用...

    宋华 评论0 收藏0
  • Entity Framework 继承映射

    摘要:一是常用的策略,通过外键来表示继承,父类和子类分别位于不同的表中,子类表包含自身属性列和父类表的外键,并将父表的外键作为子类表的主键。与父类的多态关联将被表示为引用父类表的外键。 继承是面向对象开发时经常用到的,但是SQL Server 数据库不具备继承,那么怎么办能?我们可以利用如下三种方法: TPH(Table per Hierachy):对SQL架构进行非规范化来表示多态,使用...

    microelec 评论0 收藏0

发表评论

0条评论

阅读需要支付1元查看
<