0

我是一名試圖首先獲取EF代碼以讓我在SQL中執行2分鐘內完成的操作的沉船殘骸。如果我已經花了5天的時間試圖使它工作,我只需在DDL中編寫我的數據庫並使用ADO.NET。但我離題...如何在EF 5 Code First中使用一個Bar作爲Foo

我想有2個表,其中A中的每個記錄都有一個相應的記錄B.他們都是同一個對象的一部分;他們需要在單獨的桌子上,因爲我不會去(但他們真的這樣做,所以不要去那裏)。如果我是從數據庫端進行設計的,我只需要從B到A的FK關係。

在EF代碼中,我試過使用shared primary key methodone-to-one foreign key association方法,但都不適用於我。我也試過了所有我能想到的變體的100個左右的組合,而且我沒有進一步前進。

正如我所說的,我想要的是一個可導航的關係從A到B(和後面會很好,但我讀過這是不可能的),並且該關係是惰性加載,所以我可以說a.b並有權訪問b的字段。

我不可能一一列舉所有我試過的東西,所以讓我就給什麼作品爲例:

class Foo 
{ 
    public int Id { get; set; } 
    public string FooProperty { get; set; } 

    public virtual Bar Bar { get; set; } 
} 

class Bar 
{ 
    public int Id { get; set; } 
    public string BarProperty { get; set; } 
} 

注意,有一個從酒吧沒有向後引用美孚,因爲(a)SQL Server會抱怨多個級聯刪除路徑,並且(b)EF會抱怨不知道哪一邊是該關聯的主要端點。所以...很好 - 我可以沒有它。

這是什麼讓我的數據庫是一個FoosIdFooPropertyBar_Id領域和BarsIdBarProperty領域。這與我在SQL中建模的方式非常接近,但我可能會將FK字段放在Bar而不是Foo。但是,因爲它是1:1,所以這並不重要,我想。

我說,這幾乎成功運作的原因是,如果我添加Bar和相關Foo,然後加載它們放回時,Foo對象的Bar屬性爲null。

using (var dbContext = new MyDbContext()) 
{ 
    var foo = dbContext.Foos.Create(); 
    foo.FooProperty = "Hello"; 
    dbContext.Foos.Add(foo); 

    var bar = dbContext.Bars.Create(); 
    bar.BarProperty = "world"; 

    foo.Bar = bar; 

    dbContext.SaveChanges(); 
} 

using (var dbContext = new MyDbContext()) 
{ 
    foreach (var foo in dbContext.Foos) 
     Console.WriteLine(foo.Bar.Id); // BOOM! foo.Bar is null 
} 

我通常會想到的foo.Bar評估觸發Bar對象的延遲加載,但它不會 - 該屬性仍然null

我該如何解決?

回答

3

Thsi應該工作:

語境

public class FoobarCtx : DbContext 
{ 
    public DbSet<Bar> Bars { get; set; } 
    public DbSet<Foo> Foos { get; set; } 

    public FoobarCtx() 
    { 

    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Bar>() 
      .HasRequired(f => f.Foo) 
      .WithRequiredDependent(b => b.Bar) 
      .Map(x => x.MapKey("FooId")) 
      .WillCascadeOnDelete(true); 
    } 
} 

實體

public class Foo 
{ 
    public int Id { get; set; } 

    public string Foo1 { get; set; } 
    public string Foo2 { get; set; } 

    public virtual Bar Bar { get; set; } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public string Bar1 { get; set; } 
    public string Bar2 { get; set; } 

    public virtual Foo Foo { get; set; } 
} 

我測試了它在EF 4.3,但我認爲它應該也可以在EF5。關鍵是OnModelCreating方法。您可以將其中一個或另一個定義爲主體/後代,並擺脫Microsoft SQL限制。

欲瞭解更多信息,請參閱此blog-post。有關模型構建器(流利API)的更多信息,請轉至here

要啓用延遲加載,請使用DbContext.FooSet.Create()方法。示例here

+0

@LueTim:謝謝,但這不**工作。這是我嘗試過的很多事情之一(實際上,這篇博客文章與我在我的問題中提到的那篇博客文章是一樣的 - 這似乎是大家*指出的一件事!)。 – 2012-08-06 21:13:33

+0

所以,我從中得到的是帶有Id和BarId字段的Foos表格,以及帶有Id和FooId字段的Bars表格。只有Bars表中的Id是標識列,並且兩個Id列之間有FK關係。 – 2012-08-06 21:15:34

+0

代碼運行時,Foo對象的Bar屬性與以前一樣爲null。更糟糕的是,在對象和數據庫中,框架都沒有設置FooId和BarId字段。EF似乎完全忽略了它們。所以實際上這個特定的配置功能遠不如我的問題的出發點。 – 2012-08-06 21:16:41

0

作爲提醒自己,如果沒有別的......

LueTm到達所產生的表結構我本來考慮(在酒吧表中的列FooId)的解決方案,以及獨立的PK上兩張桌子。如果沒有使用dbContext.Foos.Include(f => f.Bar)加載它,仍然無法訪問Foo.Bar屬性。

我還能夠使用共享主鍵使事情工作得很好(兩個表都有一個PK,但Foos中只有一個是身份(自動增量)列,而且有一個FK關係在酒吧中的Id到Fo中的Id

爲此,我在Foo類中有一個Bar屬性,在Bar類中有一個Foo屬性(因此雙向導航工作),並將以下內容放入我的OnModelCreating。

modelBuilder.Entity<Bar>() 
       .HasRequired(x => x.Foo) 
       .WithRequiredDependent(x => x.Bar) 
       .WillCascadeOnDelete(true); 

modelBuilder.Entity<Foo>() 
       .HasRequired(x => x.Bar) 
       .WithRequiredPrincipal(x => x.Foo) 
       .WillCascadeOnDelete(true); 

(我不知道的是,第二次調用這裏實際上沒有任何東西)。

但是,您仍然需要撥打Include()才能訪問foo.Bar

0

我剛剛經歷過這個自己。我有一個FoodEntry,一個Food,而這個Food有一個FoodGroup。

public class FoodEntry 
{ 
    public int  Id { get; set; } 
    public string User { get; set; } 
    public Food  Food { get; set; } 
    public decimal PortionSize { get; set; } 
    public Portion Portion { get; set; } 
    public int  Calories { get; set; } 
    public Meal Meal { get; set; } 
    public DateTime? TimeAte { get; set; } 
    public DateTime EntryDate { get; set; } 
} 

public class Food 
{ 
    public int  Id { get; set; } 
    public string Name { get; set; } 
    public FoodGroup FoodGroup { get; set; } 
} 

public class FoodGroup 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

我先使用代碼,並且我的POCO類的定義與您的定義一樣。我沒有標記爲虛擬的屬性。

在任何情況下,數據庫都會像我期望的那樣生成 - 使用您所描述的外鍵。

但此查詢導致剛開FoodEntry收集在食品,部分和膳食性空:

var foodEntries = db.FoodEntries 
      .Where(e => e.User == User.Identity.Name).ToList(); 

我改變了查詢到這一點,並加載回來收集整個圖形:

var foodEntries = db.FoodEntries 
      .Include(p => p.Food) 
      .Include(p => p.Food.FoodGroup) 
      .Include(p => p.Portion) 
      .Include(p => p.Meal) 
      .Where(e => e.User == User.Identity.Name).ToList() 
      ; 
0

對於1:1關係除了 1:許多關係(美孚具有若干條,並且也是CurrentBar):

 modelBuilder.Entity<Foo>() 
      .HasOptional(f => f.CurrentBar) 
      .WithMany() 
      .HasForeignKey(f => f.CurrentBarId); 

     modelBuilder.Entity<Bar>() 
      .HasRequired(b => b.Foo) 
      .WithMany(f => f.Bars) 
      .HasForeignKey(b => b.FooId); 
相關問題