entity framework/代码优先/ table-per-typeinheritance – 实现派生类和具体类之间的一对多关联

我在VS2012中使用MVC4,我遵循每个类型的表inheritance方法。 我正在尝试使用Seed()方法将数据添加到我的数据库。

我有以下课程:

房东

 [Table("Landlord")] public class Landlord : UserProfile { // A Landlord can have many ResidentialProperties [ForeignKey("ResidentialPropertyId")] public virtual ICollection ResidentialProperties { get; set; } } 

ResidentialProperty

 [Table("ResidentialProperty")] public class ResidentialProperty { [Key] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int ResidentialPropertyId { get; set; } // A ResidentialProperty has 1 Landlord public virtual int UserId { get; set; } public virtual UserProfile UserProfile { get; set; } } 

所以Landlordinheritance自UserProfile ,因此Landlord.没有PK属性Landlord.

我想要实现的关系如下:

  • Landlord可以有很多ResidentialProperties (1:n)
  • ResidentialProperty可以(在申请范围内)有一个Landlord (1:1)

我认为我配置模型的方式足以成功地从包管理器运行update-database命令,并将我在Seed()方法中的内容添加到我的数据库中。 事实并非如此,我收到以下错误:

无法确定’LetLord.Models.ResidentialProperty_UserProfile’关系的主要结尾。 多个添加的实体可以具有相同的主键。

阅读后我意识到我想要创建的关系需要使用Fluent API实现,所以我尝试了以下内容:

  modelBuilder.Entity() .HasMany(x => x.ResidentialProperties) .WithOptional() .HasForeignKey(x => x.ResidentialPropertyId); modelBuilder.Entity() .HasRequired(x => x.UserProfile); 

当我尝试通过包管理器执行update-database命令时,我收到以下错误:

\ tSystem.Data.Entity.Edm.EdmAssociationEnd ::多重性在关系’Landlord_ResidentialProperties’中的角色’Landlord_ResidentialProperties_Target’中无效。 由于“从属角色”是指关键属性,因此从属角色的多重性的上限必须为“1”。

我完全不知道如何解决我的问题。 我花了很多时间坚持这一点,这非常令人沮丧,因为我觉得这应该很容易实现。 如果有人有解决方案,如果你能与我分享,我将非常感激。

编辑 – 从上面提到的第一个错误抛出的exception输出:

System.Data.Entity.Infrastructure.DbUpdateException:无法确定“LetLord.Models.ResidentialProperty_Landlord”关系的主要结尾。 多个添加的实体可以具有相同的主键。 —> System.Data.UpdateException:无法确定’LetLord.Models.ResidentialProperty_Landlord’关系的主要结尾。 多个添加的实体可以具有相同的主键。 System.Data.Mapping.Update.Uternal中的System.Data.Mapping.Update.Uternal.UpdateTranslator.RegisterEntityReferentialConstraints(IEntityStateEntry stateEntry,Boolean currentValues)at System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterReferentialConstraints(IEntityStateEntry stateEntry)。 System.Data.EntityClient.EntityAdapter上System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager,IEntityAdapter适配器)的System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()中的UpdateTranslator.PullModifiedEntriesFromStateManager() System.Data.Entity.Internal.InternalContext.SaveChanges()中System.Data.Objects.ObjectContext.SaveChanges(SaveOptions选项)的.Update(IEntityStateManager entityCache)—内部exception堆栈跟踪结束—在System.Data位于LetLord.Migration的System.Data.Entity.DbContext.SaveChanges()的System.Data.Entity.Internal.LazyInternalContext.SaveChanges()处的.Entity.Internal.InternalContext.SaveChanges() s.Configuration.Seed(LetLordContext context)位于c:\ Users \ Home \ Desktop \ LetLord \ LetLord \ Migrations \ Configuration.cs:第83行

编辑 – 解决方案:

实体应该按照Ladislav的回答,我的错误是在基类的许多方面制作导航属性,而不是派生类。

我的下一个错误是我的Seed()方法中的实体排序。 我在下面添加了它们应该是什么样的,这尤其适用于添加具有关联的实体。

  protected override void Seed(LetLord.Models.LetLordContext context) { try { #region Landlords // create a list of landlords first - a landlord can have many residential properties, make this = new List() var landlords = new List { // landlord 1 new Landlord { UserName="Frank", FirstName="Frank", LastName="O'Sullivan", Email="a@a.com", AccountType=(int)AccountType.Landlord, ResidentialProperties = new List() } // ... }; landlords.ForEach(l => context.UserProfile.AddOrUpdate(l)); context.SaveChanges(); #endregion #region ResidentialProperties // then create a list of properties var residentialProperties = new List { // Property 1 associated with LandLord 1 new ResidentialProperty { PropTypeValue=(int)PropertyType.Detached, Description="Some description...", NumberOfBedrooms="4", NumberOfReceptionRooms="2", NumberOfBathrooms="2", HasBackGarden=true, HasFrontGarden=true, HasSecureParking=false, IsDisabledFriendly=false, DateAdded=DateTime.Now, Landlord = landlords.FirstOrDefault(u => u.UserId == 11) } // in my case, user 11 is landlord 1 // ... }; residentialProperties.ForEach(rp => context.ResidentialProperty.AddOrUpdate(rp)); context.SaveChanges(); #endregion // then add our list of properties to our list of landlords landlords[0].ResidentialProperties.Add(residentialProperties[0]); landlords[1].ResidentialProperties.Add(residentialProperties[1]); landlords[2].ResidentialProperties.Add(residentialProperties[2]); landlords[3].ResidentialProperties.Add(residentialProperties[3]); landlords[4].ResidentialProperties.Add(residentialProperties[4]); landlords[5].ResidentialProperties.Add(residentialProperties[5]); landlords[6].ResidentialProperties.Add(residentialProperties[6]); landlords[7].ResidentialProperties.Add(residentialProperties[7]); landlords[8].ResidentialProperties.Add(residentialProperties[8]); landlords[9].ResidentialProperties.Add(residentialProperties[9]); context.SaveChanges(); } catch (Exception ex) { string lines = ex.ToString(); System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Users\Home\Desktop\error.txt"); file.WriteLine(lines); file.Close(); } 

当我在修复代码之后尝试运行update-database ,我遇到了这个错误:

System.Data.Entity.Infrastructure.DbUpdateException:更新条目时发生错误。 有关详细信息,请参阅内部exception —> System.Data.UpdateException:更新条目时发生错误。 有关详细信息,请参阅内部exception —> System.Data.SqlClient.SqlException:INSERT语句与FOREIGN KEY约束“FK_dbo.ResidentialProperty_dbo.Landlord_UserId”冲突。 冲突发生在数据库“C:\ USERS \ HOME \ DESKTOP \ LETLORD \ LETLORD \ APP_DATA \ LETLORD.MDF”,表“dbo.Landlord”,列’UserId’中。 该语句已终止。

快速搜索后,我发现这个错误正在引起(我认为),因为我的数据库中已有数据。 删除并重新创建数据库就是这个问题,当我再次运行Seed()方法时,数据已成功添加。

如果房东可以有多个房产,房产可以有多个房东,那么模型应该是这样的:

 [Table("Landlord")] public class Landlord : UserProfile { // A Landlord can have many ResidentialProperties public virtual ICollection ResidentialProperties { get; set; } } [Table("ResidentialProperty")] public class ResidentialProperty { [Key] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int ResidentialPropertyId { get; set; } // A ResidentialProperty has 1 Landlord // Foreign key is on many side and it contains value of primary key on one side // In your case FK must contain value of property's landlord public virtual int UserId { get; set; } // ForeignKey attribute pairs navigation property on many side with foreign key propety [ForeignKey("UserId")] public virtual Landlord Landlord { get; set; } }