C# EF代码优先:定义外键

C# EF代码优先:定义外键,c#,entity-framework-4,ef-code-first,C#,Entity Framework 4,Ef Code First,我看了一些其他的答案和很多文章,但这个简单的部分仍然让我摸不着头脑。我使用的是EF code first 4.1,但如果它更简单的话,我很乐意升级到新版本。我有一个这样的主事实表: namespace Spend.Models { public class ExpenseItem { [Key] public String UniqueID_ERLineID { get; set; } public String ERNum { g

我看了一些其他的答案和很多文章,但这个简单的部分仍然让我摸不着头脑。我使用的是EF code first 4.1,但如果它更简单的话,我很乐意升级到新版本。我有一个这样的主事实表:

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,但我希望它将这些字段指定为链接。任何关于如何做到这一点的帮助都将不胜感激

另外,我目前无法重命名数据库字段

@卢克:

我应用了你提到的变化,它们是有意义的。但是,我得到以下错误:

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或类似的东西——我需要在ExpenseItem定义中添加一些东西来实现这一点吗

我的模型设置如下。base.OnModelCreating是通过intellisense出现的,我尝试过使用/不使用它,得到了相同的结果:

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);
    }
}
公共类SpendDB:DbContext
{
公共DbSet ExpenseAttachments{get;set;}
公共数据库集ExpenseComments{get;set;}
公共数据库集ExpenseCountings{get;set;}
公共数据库集ExpenseItemFbtItems{get;set;}
公共数据库集ExpenseItems{get;set;}
公共数据库集ExpenseItemViolations{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Entity().HasOptional(e=>e.ExpenseItem)。WithMany().HasForeignKey(e=>e.UniqueID\U Accounting);
}
}
也许我需要将虚拟ICollection放入ExpenseItem定义中?或者可能是另一种情况——比如modelBuilder.Entity有可选的ExpenseItemAccounting?对我来说,这听起来更直观,但我(显然)不太擅长这一点,所以对此持怀疑态度

再次感谢

请执行以下操作:

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中使用

modelBuilder.Entity<ExpenseItemAccounting>()
    .HasOptional(e => e.ExpenseItem).WithMany()
    .HasForeignKey(e => e.UniqueID_Accounting );
并使用modelBuilder for config:

modelBuilder.Entity<ExpenseItemAccounting>()
    .HasOptional(e => e.ExpenseItem)
    .WithOptionalDependent(e=>e.Parent_Expense_Item);
modelBuilder.Entity()
.has可选(e=>e.ExpenseItem)
.具有可选依赖项(e=>e.母公司费用项目);
我认为,如果你还想连接FK引用(不仅仅是导航属性),你需要在一个单独的语句中这样做,但这有点复杂

看看MSDN页面上的导航属性,以及如何使用modelBuilder,因为它有很多高级内容的好例子


解决方案之一是将ERLineID的可空值更改为TRUE

你好,卢克,谢谢你。这里没有充分解释的余地-请参阅原始问题中我遇到错误的地方的编辑。任何进一步的意见将是伟大的@Glinkot是的,你完全可以让关系双向发展,只需使用lambda在withMany中指定你的集合。我将更新我的帖子以反映这一点您在此处遇到的错误是因为导航属性使用了.WithOptional,并且您的DB具有不可为空的密钥。您可以简单地将modelBuilder更改为使用。WithRequired应该可以解决此问题。此外,在您的linq查询中,您正在自己进行连接,您可以使用navigation属性为您执行此操作,并简化您的查询,例如从db.ExpenseItemFbtItems中的f。。。选择f.ExpenseItem…'
 modelBuilder.Entity<ExpenseItemAccounting>()
     .HasOptional(e => e.ExpenseItem).WithMany(e=> e.ExpenseItems)
     .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 Card_Number { get; set; }
            public ExpenseItemAccounting Parent_Expense_Item { get; set; }
    }
modelBuilder.Entity<ExpenseItemAccounting>()
    .HasOptional(e => e.ExpenseItem)
    .WithOptionalDependent(e=>e.Parent_Expense_Item);