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類後,咱們編寫將數據存入數據庫的方法:ui

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.pngspa

出現上述錯誤的緣由是咱們沒有初始化 Address 類,其中一個(後面我會講解另外一個解決方法)解決方法是在 new User(){} 內初始化 Address,修正後的代碼以下:code

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、如何正確使用複雜類型

  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 。咱們看一下訪問原始值和當前值得例子:ip

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.pngci

一樣,咱們也能夠經過鏈式調用,獲取複雜了類型的屬性或者設置複雜類型的屬性:rem

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

2、複雜類型的限制

從上面的講解咱們卡一看到,用複雜類型很雙,一直用一直爽,可是複雜類型仍是有他的限制的:get

  1. 不能共享引用:由於沒有主鍵標識,不能被自身實例以外的任何對象引用;
  2. 沒有優雅的方式標識空引用:即便查詢出的數據爲空,EF Code First 依然會初始化複雜類型對象;
  3. 沒法延遲加載。
相關文章
相關標籤/搜索