【问题标题】:Two One-to-Many relationships in the same table同一个表中的两个一对多关系
【发布时间】:2014-02-19 23:02:45
【问题描述】:

我有一个名为SystemAccount 的表,它(直到最近)有一个MasterAccountID 指向它的父帐户(显然是一个int?)。我的客户现在告诉我,有时一个帐户可能有 2 个父帐户(没有一个超过这个帐户)。我一直在尝试在我的 SystemAccount 课程中进行调整,但它并没有产生我想要的关系。

这是部分课程代码:

[ForeignKey("MasterAccount")]
public int? MasterAccountID { get; set; }

[ForeignKey("SecondMasterAccount")]
public int? SecondMasterAccountID { get; set; }

public virtual SystemAccount MasterAccount { get; set; }

public virtual SystemAccount SecondMasterAccount { get; set; }

public virtual List<SystemAccount> AllSubAccounts { get; set; }

public virtual List<SystemAccount> SecondarySubAccounts { get; set; }

当我这样做时,我在表中得到 4 个 FK,其中 2 个是自动生成的(SystemAccount_IDSystemAccount_ID1)。我什至尝试将[InverseProperty] 属性放在MasterAccountSecondMasterAccount 上以指向列表,每次都会给我一个错误(编辑:它给我一个NullReferenceException)。

我知道我应该将其变为多对多关系,但我很快就要面临最后期限了,重构 MasterAccountMasterAccountID 的使用需要我远远超过最后期限。

我怎样才能让它工作?

编辑:异常堆栈跟踪:

System.NullReferenceException was unhandled by user code
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=EntityFramework
  StackTrace:
       at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EdmEntityType entityType, EdmModel model)
       at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel model)
       at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(EdmModel model)
       at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
       at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
       at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
       at System.Data.Entity.Migrations.Extensions.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
       at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(Action`1 writeXml)
       at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(DbContext context)
       at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
       at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
       at System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext context)
       at System.Data.Entity.Database.<>c__DisplayClass2`1.<SetInitializerInternal>b__0(DbContext c)
       at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass8.<PerformDatabaseInitialization>b__6()
       at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
       at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
       at System.Data.Entity.Database.Initialize(Boolean force)
       at Tests.Core.UI.SessionStartTests.ShouldSuccessfullyInitializeDatabase() in c:\Projects\Current\tests\Tests.Core\UI\StartTests.cs:line 72
  InnerException: 

编辑 2:当我使用 Moho 的建议时:

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

\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SystemAccount_AllSubAccounts_Target' in relationship 'SystemAccount_AllSubAccounts'. Valid values for multiplicity for the Principal Role are '0..1' or '1'.
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SystemAccount_AllSubAccounts_Source' in relationship 'SystemAccount_AllSubAccounts'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SystemAccount_SecondarySubAccounts_Target' in relationship 'SystemAccount_SecondarySubAccounts'. Valid values for multiplicity for the Principal Role are '0..1' or '1'.
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SystemAccount_SecondarySubAccounts_Source' in relationship 'SystemAccount_SecondarySubAccounts'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

编辑 3:我更新数据库的代码:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>());
var db = new MyDbContext();
db.Database.Initialize(true);

我的OnModelCreating 方法:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

modelBuilder.Entity<ClientStatisticsView>().ToTable("ClientStatistics");

base.OnModelCreating(modelBuilder);

我的Configuration 文件:

public Configuration()
{
  AutomaticMigrationsEnabled = true;
  AutomaticMigrationDataLossAllowed = true;
}

protected override void Seed(MyDbContext context)
{
}

【问题讨论】:

  • 我猜code是来自系统账号,能不能发一下master账号,以及两者的关系
  • 主账号来自同一张表。它本身就是一对多的。
  • 使用[InverseProperty] 属性时遇到的错误是什么? (该属性本来是我解决问题的建议......)
  • 我在以下代码行中得到了一个NullReferenceException(即使我调试它时没有任何内容):db.Database.Initialize(true);
  • 我刚刚使用 EF 6 测试了模型([InverseProperty("AllSubAccounts")]MasterAccount[InverseProperty("SecondarySubAccounts")]SecondMasterAccount)。我没有得到异常,但是具有两个 FK 的预期数据库模式。异常是否可能发生在Seed 方法中?你能显示堆栈跟踪吗?

标签: c# entity-framework ef-code-first entity-framework-5


【解决方案1】:

您是否尝试过使用InverseProperty 属性装饰集合属性?

[InverseProperty( "MasterAccount" )]
public virtual List<SystemAccount> AllSubAccounts { get; set; }

[InverseProperty( "SecondMasterAccount" )]
public virtual List<SystemAccount> SecondarySubAccounts { get; set; }

这是一个适合我的演示:

public class HierarchicalEntity
{
    public int Id { get; set; }
    public string Description { get; set; }

    [ForeignKey( "PrimaryParent" )]
    public int? PrimaryParentId { get; set; }

    [ForeignKey( "SecondaryParent" )]
    public int? SecondaryParentId { get; set; }
    public virtual HierarchicalEntity PrimaryParent { get; set; }

    public virtual HierarchicalEntity SecondaryParent { get; set;}

    [InverseProperty( "PrimaryParent" )]
    public ICollection<HierarchicalEntity> ChildrenViaPrimaryParent { get; set; }

    [InverseProperty( "SecondaryParent" )]
    public ICollection<HierarchicalEntity> ChildrenViaSecondaryParent { get; set; }
}

【讨论】:

  • 你有没有显示的流畅的 api 配置?
  • 不。就是这个:modelBuilder.Conventions.Remove&lt;OneToManyCascadeDeleteConvention&gt;();
  • 我刚刚尝试输入您的确切示例,但它仍然给我同样的错误。我的迁移设置有问题吗?
【解决方案2】:

我现在用 EF 5 重现了这个问题。在应用 Moho 的代码时,我得到了完全相同的异常和堆栈跟踪以及 EDIT 2 中的异常。 EF 6 不会出现此问题。因此,如果您可以选择升级到 EF 6 来解决问题。

如果您需要使用 Fluent API 映射而不是使用 [InverseProperty] 属性来坚持使用 EF 5,则对我来说毫无例外。然后您可以删除所有属性:

public class SystemAccount
{
    public int ID { get; set; }

    public int? MasterAccountID { get; set; }
    public int? SecondMasterAccountID { get; set; }

    public virtual SystemAccount MasterAccount { get; set; }
    public virtual SystemAccount SecondMasterAccount { get; set; }

    public virtual List<SystemAccount> AllSubAccounts { get; set; }
    public virtual List<SystemAccount> SecondarySubAccounts { get; set; }
}

与 Fluent API 的关系映射:

modelBuilder.Entity<SystemAccount>()
    .HasOptional(s => s.MasterAccount)
    .WithMany(s => s.AllSubAccounts)
    .HasForeignKey(s => s.MasterAccountID);

modelBuilder.Entity<SystemAccount>()
    .HasOptional(s => s.SecondMasterAccount)
    .WithMany(s => s.SecondarySubAccounts)
    .HasForeignKey(s => s.SecondMasterAccountID);

[InverseProperty] 属性与您的模型导致异常的事实似乎是 EF 5 中的一个错误。该错误很可能与自引用类型的关系有关,因为通常与不同实体之间的关系该属性有效没有问题。

【讨论】:

    【解决方案3】:

    我的解决方案基于我从 @Slauma 和 @Moho 那里得到的建议(为你们俩+1 的帮助!)。

    [InverseProperty] 属性确实是缺少的,但是当我将它放在文件上时它不起作用。然后,当我在一个全新的文件中尝试@Moho 的代码时,它仍然无法正常工作。所以我将[ForeignKey] 属性从 ID 字段切换到对象字段本身,即:

    public int? PrimaryParentId { get; set; }
    public int? SecondaryParentId { get; set; }
    
    [ForeignKey( "PrimaryParent" )]
    public virtual HierarchicalEntity PrimaryParent { get; set; }
    
    [ForeignKey( "SecondaryParent" )]
    public virtual HierarchicalEntity SecondaryParent { get; set;}
    

    这最终奏效了。但是当我尝试在我的SystemAccount 班级上这样做时,它就行不通了。所以我最终做了以下步骤来让它工作:

    1. 已注释掉列表对象、父记录以及两个字段的 FK 属性。
    2. 已迁移数据库。现在所有 FK 都被丢弃了。
    3. 取消注释
    4. 检查[InverseProperty] 属性是否在列表对象上,并将[ForeignKey] 属性放在virtual 对象上。
    5. 已迁移数据库。唯一出现的外援是我想成为外援的人!

    我知道这是一个奇怪的解决方案,但只要它有效......

    【讨论】:

    猜你喜欢
    • 2011-08-10
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    相关资源
    最近更新 更多