2012-03-08 201 views
2

我已經看了一些其他的答案和很多文章,但這個簡單的部分仍然逃避我。我首先使用EF代碼4.1,但如果它更容易轉移到新版本,我很樂意。我有一個主要的事實表像這樣:EF代碼優先:定義外鍵

namespace Spend.Models 
{ 
    public class ExpenseItem 
    { 
     [Key] 
     public String UniqueID_ERLineID { get; set; } 
     public String ERNum { get; set; } 
     public String ItemNum { get; set; } 
     public String Parent_Expense_Item { get; set; } 
     public String Card_Number { get; set; } 
... 

和幾個表掛這裏面有許多與ExpenseItems一個關係:

public class ExpenseItemAccounting 
{ 
    [Key] 
    public String UniqueID_Accounting { get; set; } 
    public String ERLineID { get; set; } 
    public String ERNum { get; set; } 
    public String ItemNum { get; set; } 

正如我們所看到的,在第二個表中ERLineID首先加入到UniqueID_ErLineID,所以我通常依賴的'約定'不起作用。所以我需要使用虛擬ICollection - 但我希望它將這些字段指定爲鏈接。如何做到這一點的任何幫助表示讚賞。

PS。目前我無法重命名數據庫字段。

@LUKE:

我應用了你提到的改變,它們有意義。我碰到下面的錯誤但是:

System.Data.Entity.ModelConfiguration.ModelValidationException occurred 
    Message=One or more validation errors were detected during model generation: 

    System.Data.Edm.EdmAssociationType: : Multiplicity conflicts with the referential constraint in Role 'ExpenseItemAccounting_ExpenseItem_Target' in relationship 'ExpenseItemAccounting_ExpenseItem'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'. 
    System.Data.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'ExpenseItemAccounting_ExpenseItem_Source' in relationship 'ExpenseItemAccounting_ExpenseItem'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be �1�. 

    Source=EntityFramework 
    StackTrace: 
     at System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateAndSerializeCsdl(EdmModel model, XmlWriter writer) 
     at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo) 
     at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) 
     at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) 
     at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) 
     at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() 
     at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) 
     at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() 
     at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() 
     at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() 
     at System.Linq.Queryable.SelectMany[TSource,TCollection,TResult](IQueryable`1 source, Expression`1 collectionSelector, Expression`1 resultSelector) 
     at EmailClient.Prog.getData() in C:\MF\Dropbox\Dev_LN_Projects\04_QA\EmailClient\EmailClient\Prog.cs:line 172 
    InnerException: 

在此之前,當我嘗試以下LINQ查詢:

 var geee = (from e in db.ExpenseItems 
         from f in db.ExpenseItemFbtItems 
         where 
         e.Item_Transaction_Date.Value.Year == 2011 && 
         e.Item_Transaction_Date.Value.Month == 8 
         select new { A = e.UniqueID_ERLineID, B = f.ERLineID.First() }); 

其實我希望能夠說e.ExpenseItemAccounting.ItemNum或類似的東西 - DO我需要在ExpenseItem定義中加入一些東西來達到這個目的?

我的模型使用以下設置。該base.OnModelCreating通過智能感知出現了,我和/試過了,沒有它的相同的結果:

public class SpendDB : DbContext 
{ 
    public DbSet<ExpenseAttachment> ExpenseAttachments {get; set; } 
    public DbSet<ExpenseComment> ExpenseComments {get; set; } 
    public DbSet<ExpenseItemAccounting> ExpenseAccountings {get; set; } 
    public DbSet<ExpenseItemFbtItem> ExpenseItemFbtItems {get; set; } 
    public DbSet<ExpenseItem> ExpenseItems {get; set; } 
    public DbSet<ExpenseItemViolation> ExpenseItemViolations {get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 
     modelBuilder.Entity<ExpenseItemAccounting>().HasOptional(e => e.ExpenseItem).WithMany().HasForeignKey(e => e.UniqueID_Accounting); 
    } 
} 

也許我需要把虛擬的ICollection中的ExpenseItem定義是什麼?或者它可能是相反的 - 比如modelBuilder.Entity有可選的ExpenseItemAccounting?這對我來說聽起來更直觀,但我(顯然)不是很擅長這個,所以拿一粒鹽吧!

再次感謝

+0

你在這裏的錯誤是因爲導航屬性使用.WithOptional,和您的數據庫有一個非空的關鍵。您可以簡單地將modelBuilder更改爲使用.WithRequired,它應該可以解決此問題。 – 2012-03-08 08:09:19

+0

也在你的linq查詢中你自己正在做連接,你可以使用導航屬性來爲你做這件事,並簡化你的查詢,例如從db.ExpenseItemFbtItems中的f ... select f.ExpenseItem ...' – 2012-03-08 08:12:49

回答

2

這樣做:在你的模型構建器中使用

public class ExpenseItemAccounting 
{ 
    [Key] 
    public String UniqueID_Accounting { get; set; } 
    public ExpenseItem ExpenseItem{get;set;} 
    public String ERLineID { get; set; } 
    public String ERNum { get; set; } 
    public String ItemNum { get; set; } 
} 

然後

modelBuilder.Entity<ExpenseItemAccounting>().HasOptional(e => e.ExpenseItem).WithMany().HasForeignKey(e => e.UniqueID_Accounting); 

編輯:

要配置的導航屬性對其他集合最後你可以簡單地像這樣添加它

public class ExpenseItem 
{ 
     [Key] 
     public String UniqueID_ERLineID { get; set; } 
     public String ERNum { get; set; } 
     public String ItemNum { get; set; } 
     public String Parent_Expense_Item { get; set; } 
     public String Card_Number { get; set; } 
     public ICollection<ExpenseItemAccounting> ExpenseItemAccountings{ get; set; } 
} 

然後通過修改模型構建器配置接線起來如下:

modelBuilder.Entity<ExpenseItemAccounting>().HasOptional(e => e.ExpenseItem).WithMany(e=> e.ExpenseItems).HasForeignKey(e => e.UniqueID_Accounting); 

這將連線起來,使的ExpenseItem將所有孩子的ExpensItemAccounting的列表,你還可以添加一個奇異這個版本是否更有意義,如:

public class ExpenseItem 
    { 
      [Key] 
      public String UniqueID_ERLineID { get; set; } 
      public String ERNum { get; set; } 
      public String ItemNum { get; set; } 
      public String Card_Number { get; set; } 
      public ExpenseItemAccounting Parent_Expense_Item { get; set; } 
    } 

和使用模型構建器進行配置:

modelBuilder.Entity<ExpenseItemAccounting>().HasOptional(e => e.ExpenseItem).WithOptionalDependent(e=>e.Parent_Expense_Item); 

我認爲如果您還想要FK參考線(不僅僅是導航屬性),您需要在單獨的語句中執行此操作,但那會更加煩瑣。

查看導航屬性的MSDN頁面以及如何使用modelBuilder,因爲它有很多先進的東西的很好的例子。

http://msdn.microsoft.com/en-us/library/hh295843(v=vs.103).aspx

+0

Hi Luke ,謝謝你。沒有足夠的空間在這裏完整地解釋 - 請參閱我在原始問題中編輯我遇到錯誤的地方。任何進一步的意見將是偉大的! – Glinkot 2012-03-08 04:40:22

+0

@Glinkot是的,你絕對可以讓關係走兩邊路,只需要用一個lambda來在withMany中指定你的集合。生病更新我的帖子,以反映這 – 2012-03-08 07:51:12

+0

偉大的盧克,感謝所有這些細節! – Glinkot 2012-03-08 22:40:04

0

解決的辦法之一是改變ERLineID的空值設置爲TRUE