2012-11-01 64 views
0

如何使用代碼優先和流利的api設置這些表關係的映射?實體框架4.2代碼優先流利的api映射中間表

我對創建的所有三個實體都有一個poco,但大多數人沒有「中間」表的poco(PlanUser),所以我找不到一個很好的例子。我要告訴EF到PlanUser.PlanCustomerId列映射到Plan.CustomerId但它要麼不返回當前設置正確的結果,或作爲計劃映射引發錯誤:

"The specified association foreign key columns 'CustomerId' are invalid. The number of columns specified must match the number of primary key columns."

enter image description here enter image description here

public class PlanUserMap : EntityTypeConfiguration<PlanUser> 
{ 
    public PlanUserMap() 
    { 
     this.ToTable("PlanUser"); 
     this.HasKey(c => new { c.CustomerId, c.PlanCustomerId }); 

     this.HasRequired(c => c.Plan).WithMany().HasForeignKey(x => x.CustomerId).WillCascadeOnDelete(false); 
     this.HasRequired(c => c.Customer).WithMany().HasForeignKey(x => x.CustomerId).WillCascadeOnDelete(false); 
    } 
} 

public class PlanMap : EntityTypeConfiguration<Plan> 
{ 
    public PlanMap() 
    { 
     this.ToTable("Plan"); 
     this.HasKey(c => c.CustomerId); 
     // the below line returns only 1 row for any given customer even if there are multiple PlanUser rows for that customer 
     //this.HasMany(c => c.PlanUsers).WithRequired().HasForeignKey(c => c.PlanCustomerId); 
     // this throws an error 
     this.HasMany(c => c.PlanUsers).WithMany().Map(m => m.MapLeftKey("PlanCustomerId").MapRightKey("CustomerId")); 
    } 
} 

public partial class CustomerMap : EntityTypeConfiguration<Customer> 
{ 
    public CustomerMap() 
    { 
     this.ToTable("Customer"); 
     this.HasKey(c => c.Id); 
     this.HasMany(c => c.PlanUsers).WithRequired().HasForeignKey(c => c.CustomerId); 
    } 
} 

@Slauma,SQL簡介r顯示正在執行的這些查詢。第二個應該包括除了客戶ID 1之外的客戶ID 43,但它不包括。我不知道爲什麼它沒有檢索第二行。

exec sp_executesql N'SELECT 
[Extent1].[CustomerId] AS [CustomerId], 
[Extent1].[PlanCustomerId] AS [PlanCustomerId], 
[Extent1].[CreatedOnUtc] AS [CreatedOnUtc], 
[Extent1].[IsSelected] AS [IsSelected], 
[Extent1].[IsDeleted] AS [IsDeleted], 
[Extent1].[AccessRights] AS [AccessRights] 
FROM [dbo].[PlanUser] AS [Extent1] 
WHERE [Extent1].[CustomerId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=43 

exec sp_executesql N'SELECT 
[Extent1].[CustomerId] AS [CustomerId], 
[Extent1].[Name] AS [Name], 
[Extent1].[PlanTypeId] AS [PlanTypeId], 
[Extent1].[OrderId] AS [OrderId], 
[Extent1].[CreatedOnUtc] AS [CreatedOnUtc], 
[Extent1].[IsActive] AS [IsActive] 
FROM [dbo].[Plan] AS [Extent1] 
WHERE [Extent1].[CustomerId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1 

這是導致查詢執行的C#代碼:

public List<Plan> GetPlans() 
    { 
     List<Plan> plans = new List<Plan>(); 

     // add each plan they have access rights to to the list 
     foreach (var accessiblePlan in Customer.PlanUsers) 
     { 
      plans.Add(accessiblePlan.Plan); 
     } 

     return plans; 
    } 

回答

0

好吧,我想通了。感謝@Slauma的幫助!我們使用IOC(autofac)的存儲庫模式。我不應該在我的存儲庫服務中首先呼叫Customer.PlanUsers。我們開始解決在存儲庫服務中使用IOC的Customer實體,以快速獲取某些客戶屬性並將其置於只讀變量中。這不可避免地影響了我們,因爲我們不是實際詢問實體存儲庫,而是從實體開始,期望它充滿我們需要的所有事物,而不是預先填充的實體。

public List<Plan> GetPlans() 
    { 
     List<Plan> plans = new List<Plan>(); 
     var list = _planUserRepository.Table.Where(a => a.CustomerId == Customer.Id).ToList(); 
     foreach (var planUser in list) 
     { 
      plans.Add(planUser.Plan); 
     } 
    } 
3

我想你需要的是實際上比你試圖映射簡單:

public class PlanUserMap : EntityTypeConfiguration<PlanUser> 
{ 
    public PlanUserMap() 
    { 
     this.ToTable("PlanUser"); 
     this.HasKey(pu => new { pu.CustomerId, pu.PlanCustomerId }); 

     this.HasRequired(pu => pu.Customer) 
      .WithMany(c => c.PlanUsers) 
      .HasForeignKey(pu => pu.CustomerId) 
      .WillCascadeOnDelete(false); 

     this.HasRequired(pu => pu.Plan) 
      .WithMany(p => p.PlanUsers) 
      .HasForeignKey(pu => pu.PlanCustomerId) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class PlanMap : EntityTypeConfiguration<Plan> 
{ 
    public PlanMap() 
    { 
     this.ToTable("Plan"); 
     this.HasKey(p => p.CustomerId); 
    } 
} 

public partial class CustomerMap : EntityTypeConfiguration<Customer> 
{ 
    public CustomerMap() 
    { 
     this.ToTable("Customer"); 
     this.HasKey(c => c.Id); 
    } 
} 

我不是確定你爲什麼禁用級聯刪除。我可能不會這樣做(即我將刪除兩個關係的WillCascadeOnDelete(false)),因爲關聯實體PlanUser是依賴於其他兩個實體的類型。

以下是有關這種模型(有時稱爲「與酬許多一對多的關係」)多一點細節:Create code first, many to many, with additional fields in association table

+0

嘗試這些更改,但像原始映射任何給定的客戶返回只有1 PlanUser。我當前的客戶43數據集應該返回2個PlanUser行。我使用了SQL Profiler,查詢忽略了第二個PlanUser行。我想粘貼查詢,但此框中的字符限制有所減緩。 – TugboatCaptain

+0

@StrandedPirate:所有的導航屬性都標記爲'virtual',即'Customer.PlanUsers','PlanUser.Plan'等等。 – Slauma

+0

是的,他們是。他們應該不是? – TugboatCaptain

相關問題