同一个表中的两个一对多关系
我有一个名为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 AllSubAccounts { get; set; } public virtual List SecondarySubAccounts { get; set; }
当我这样做时,我在表中获得4个FK,其中2个是自动生成的( SystemAccount_ID
和SystemAccount_ID1
)。 我甚至试图将MasterAccount
和SecondMasterAccount
上的[InverseProperty]
属性指向列表,每次都给我一个错误(编辑:它给我一个NullReferenceException
)。
我知道我应该把它变成一个多对多的关系,但我很快就会面临一个截止日期,重构MasterAccount
和MasterAccountID
的使用将超出截止日期。
我怎样才能让它发挥作用?
编辑:exception堆栈跟踪:
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.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.b__0(DbContext c) at System.Data.Entity.Internal.InternalContext.c__DisplayClass8.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()); var db = new MyDbContext(); db.Database.Initialize(true);
我的OnModelCreating
方法:
modelBuilder.Conventions.Remove(); modelBuilder.Entity().ToTable("ClientStatistics"); base.OnModelCreating(modelBuilder);
我的Configuration
文件:
public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(MyDbContext context) { }
您是否尝试使用InverseProperty
属性修饰集合属性?
[InverseProperty( "MasterAccount" )] public virtual List AllSubAccounts { get; set; } [InverseProperty( "SecondMasterAccount" )] public virtual List 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 ChildrenViaPrimaryParent { get; set; } [InverseProperty( "SecondaryParent" )] public ICollection ChildrenViaSecondaryParent { get; set; } }
我现在用EF 5重现了这个问题。在应用Moho代码时,我得到完全相同的exception和堆栈跟踪以及编辑2中的exception。 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 AllSubAccounts { get; set; } public virtual List SecondarySubAccounts { get; set; } }
与Fluent API的关系映射:
modelBuilder.Entity() .HasOptional(s => s.MasterAccount) .WithMany(s => s.AllSubAccounts) .HasForeignKey(s => s.MasterAccountID); modelBuilder.Entity () .HasOptional(s => s.SecondMasterAccount) .WithMany(s => s.SecondarySubAccounts) .HasForeignKey(s => s.SecondMasterAccountID);
因为模型的[InverseProperty]
属性导致exception这一事实似乎是EF 5中的一个错误。该错误很可能与关系的自引用类型有关,因为通常在不同实体之间存在关系时,该属性可以正常工作。
我的解决方案基于我从@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
类上执行此操作时,它将无法正常工作。 所以我最终做了以下步骤以使其工作:
- 从两个字段中注释掉列表对象,父记录和FK属性。
- 迁移数据库。 所有FK现在都下降了。
- 取消评论它
- 检查
[InverseProperty]
属性是否在列表对象上,并将[ForeignKey]
属性放在virtual
对象上。 - 迁移数据库。 唯一出现的FK就是那些我想成为FK的人!
我知道这是一个奇怪的解决方案,但只要它有效……