2012-03-08 199 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