2016-12-23 38 views
0

這是我第一次使用代碼優先的方法。我有一張用戶表,用戶可以是普通用戶和賣家兩種類型,其中賣家從具有一些額外選項(與其他表格的關係)的用戶繼承。在EF CodeFirst中生成繼承的DBSets(Like Views)

我在想,如果我可以這樣做:

public class Seller: User 
{ 
    public virtual ICollection<WorkingDay> WorkingDays {get; set;} 
    .... 
} 

,然後在ApplicationDbContext我補充一下:

public DbSet<Seller> Sellers { get; set; } 
+0

試一試,讓我們知道! – Maarten

+0

@Maarten我知道我可以嘗試看看它是否有效。我擔心這可能會起作用,但是可能是一種糟糕或錯誤的做法,並會在項目的後期部分給我造成麻煩。 –

+2

我建議閱讀[EF Code First的繼承](https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table- per-hierarchy-tph)系列。 –

回答

1

是的,你可以在實體框架使用繼承。但是,數據庫通常不支持繼承。在數據庫中,繼承是嘲弄的。有幾種策略用於模擬繼承。

假設你有三類:

public class MyBaseItem {...} 
public class MyDerived1Item : MyBaseItem {...} 
public class MyDerived2Item : MyBaseItem {...} 

策略表每個具體類(TPC) 我用這一個最常用,如果我不需要創建MyBaseItem對象,只有MyDerived1Items或MyDerived2Items。爲了防止意外創建MyBaseItem對象,我聲明瞭MyBaseItem摘要。

該數據庫將有兩個表:一個帶有MyDerived1Items,另一個帶有MyDerived2Itemss。兩個表都將有所有MyBaseItem屬性的列。

Fluent API用於通知數據庫生成器該策略已被使用。

public MyDbContext : DbContext 
{ 
    public DbSet<MyDerived1Item> MyDerived1Items {get; set;} 
    public DbSet<MyDerived2Item> MyDerived2Items {get; set;} 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<MyDerived1Item>().Map(m => 
     { 
      m.MapInheritedProperties(); 
      m.ToTable("MyDerived1Items"); 
     }); 

     modelBuilder.Entity<MyDerived2Item>().Map(m => 
     { 
      m.MapInheritedProperties(); 
      m.ToTable("MyDerived2Items"); 
     }); 
    } 
} 

添加/修改/數據庫中刪除的項目將總是意味着訪問一個表,除非你想要做的所有衍生商品的MyBaseItems性質的東西。在這種情況下,你必須給每個派生表的元素鑄成MyBaseItem和Concat的所有派生表,如下所示:

IQueryable<MyBaseItem> someBaseItems = 
    dbContext.MyDerived1Items.Where(...).Cast<MyBaseItem>() 
    .Concat(dbContext.MyDerived2Items.Where(...).Cast<MyBaseItem>(); 

這是很容易在以後添加MyDerived3Items表。 MyDerived1Items和MyDerived2Items表不必更改。

但是,將一個屬性添加到MyBaseItem意味着將一個字段添加到派生類的所有表中。

策略表每類型(TPT)

創建三個表。每種類型都有一張桌子。包含派生項目的表格具有包含基本項目的表格的外鍵。

如果您創建了MyDerived1Item,那麼該對象將被放在兩個表中。基類的MyBaseItem屬性將位於MyBaseItems表中,並且MyDerived1Item屬性將位於MyDerived1Items表中,並與MyBaseItem中的相應項的外鍵一起使用。

我不喜歡這種方法,因爲它看起來非常像一對多關係。在數據庫中有可能有一個基項與兩個派生項具有相同的外鍵,這不是你想要的。我不確定是否可以阻止將這樣的對象添加到數據庫中。

添加/搜索/更改/刪除項目始終意味着使用兩個表格,這會使這些操作變得更慢。

但是,這種方法的優點是您可以創建MyBaseItems。所以如果你需要這樣做,考慮這個策略。每層次

How to implement Table Per Type (TPT)

表(TPH)

這種策略是實體框架的缺省值。

數據庫將有一個包含MyBaseItem,MyDerived1Item和MyDerived2Item的所有屬性的表。未使用的列被設置爲NULL。如果MyDerived1Items與MyDerived2Items幾乎相同,那麼不會有太多多餘的列。但是,如果這兩個類非常不同,那麼會有很多列設置爲空。

你將有一個表,你將有一個DbSet:

public class MyDbContext: DbContext 
{ 
    public DbSet<MyBaseItem> MyItems { get; set; } 
} 

因爲這是默認的策略,不需要流暢API。

如果你需要的是隻使用基本屬性的查詢:

IQueryable<MyBaseItem> baseItems = dbContext.MyItems 
    .Where(...); 

如果您只需要MyDerived1Items:

IQueryable<MyDerived1Item> myItems = dbContext.MyItems 
    .OfType<MyDerived1Items>() 
    .Where(...); 

,如果你希望有大量的查詢,只有基本屬性考慮這一策略,因爲這隻能訪問一個表。如果你的派生類非常不同,請重新考慮它。