实体框架/代码首先/表每个类型继承 - 实现一个派生类和具体类之间是一个一对多关联 [英] Entity Framework / code first / table-per-type inheritance - implementing a one-to-many association between a derived class and a concrete class

查看:375
本文介绍了实体框架/代码首先/表每个类型继承 - 实现一个派生类和具体类之间是一个一对多关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在VS2012使用MVC4,而我下一个表每个类型继承的方法。我试图使用种子()方法将数据添加到我的数据库。

I'm using MVC4 in VS2012, and I'm following a table-per-type inheritance approach. I'm trying to use the Seed() method to add data to my database.

我有以下类:

房东

[Table("Landlord")]
public class Landlord : UserProfile
{
    // A Landlord can have many ResidentialProperties
    [ForeignKey("ResidentialPropertyId")]
    public virtual ICollection<ResidentialProperty> 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; } 

}



所以楼主用户配置,因此没有在楼主没有PK属性。

我想实现的关系如下:


  • A 楼主可以有很多的 ResidentialProperties (1:N)

  • A ResidentialProperty 可以(在应用程序的范围内)有一个楼主(1:1)
  • A Landlord can have many ResidentialProperties (1:n)
  • A ResidentialProperty can (in the application's scope) have one Landlord (1:1)

我想我已经配置了我的模型的方式就足以运行更新数据库从包管理器命令成功,并添加什么,我有我的种子()方法到我的数据库。这是不是这样,我得到了以下错误:

I thought the way I had my models configured would be enough to run the update-database command from package manager successfully, and add what I have in my Seed() method to my database. This wasn't the case, I got the following error:

无法确定LetLord.Models.ResidentialProperty_UserProfile的主要结束关系。多补充实体可能具有相同的主键。

Unable to determine the principal end of the 'LetLord.Models.ResidentialProperty_UserProfile' relationship. Multiple added entities may have the same primary key.

阅读周围,我意识到,这种关系我想创建需要使用实施流利的API,所以我尝试了以下内容:

After reading around I realised that the relationship I wanted to create needed to be implemented using Fluent API, so I tried the following:

        modelBuilder.Entity<Landlord>()
            .HasMany(x => x.ResidentialProperties)
            .WithOptional()
            .HasForeignKey(x => x.ResidentialPropertyId);

        modelBuilder.Entity<ResidentialProperty>()
            .HasRequired(x => x.UserProfile);

当我尝试执行更新数据库通过包管理器命令我得到以下错误:

When I try to execute the update-database command via package manager I get the following error:

\tSystem.Data.Entity.Edm.EdmAssociationEnd:多重无效在关系'Landlord_ResidentialProperties角色Landlord_ResidentialProperties_Target。因为从属作用是指关键性质,上限的从属地位的多重性必须是'1'。

\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'Landlord_ResidentialProperties_Target' in relationship 'Landlord_ResidentialProperties'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.

我'在不知如何弥补我的问题完全微米。我已经花了非常多的时间停留在这一点,这是非常令人沮丧,因为这是我的感觉应该很容易实现的东西。如果任何人有解决方案,我会很感激,如果你能和我一起分享

I'm completely at a loss as to how to remedy my problem. I've spent an awful lot of time stuck on this, which is very frustrating as it is something that I feel should be accomplished easily. If anyone has the solution, I'd be very appreciative if you could share it with me.

修改 - 异常输出抛出上面提到的第一个错误:

EDIT - output of exception thrown from the first error mentioned above:

System.Data.Entity.Infrastructure.DbUpdateException:无法确定LetLord.Models的主要终点。 ResidentialProperty_Landlord的关系。多个添加实体可以具有相同的主密钥。 ---> System.Data.UpdateException:无法确定LetLord.Models.ResidentialProperty_Landlord关系的主要终点。多个添加实体可以具有相同的主密钥。
在System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterEntityReferentialConstraints(IEntityStateEntry stateEntry,布尔currentValues)在System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterReferentialConstraints
(IEntityStateEntry stateEntry)$ B $在System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands b。在System.Data.Mapping.Update.Internal.UpdateTranslator.PullModifiedEntriesFromStateManager()
()
在System.Data.Mapping.Update。 Internal.UpdateTranslator.Update(IEntityStateManager StateManager的,IEntityAdapter适配器)
在System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)在System.Data.Objects.ObjectContext.SaveChanges
(SaveOptions选项)
在System.Data.Entity.Internal.InternalContext.SaveChanges()
---内部异常堆栈跟踪的结尾---
在System.Data.Entity.Internal.InternalContext.SaveChanges()在System.Data.Entity.Internal.LazyInternalContext.SaveChanges
()在System.Data.Entity.DbContext.SaveChanges
()
在LetLord.Migrations.Configuration.Seed(LetLordContext上下文)在C:\Users\Home\Desktop\LetLord\LetLord\Migrations\Configuration.cs:线83

System.Data.Entity.Infrastructure.DbUpdateException: Unable to determine the principal end of the 'LetLord.Models.ResidentialProperty_Landlord' relationship. Multiple added entities may have the same primary key. ---> System.Data.UpdateException: Unable to determine the principal end of the 'LetLord.Models.ResidentialProperty_Landlord' relationship. Multiple added entities may have the same primary key. at System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterEntityReferentialConstraints(IEntityStateEntry stateEntry, Boolean currentValues) at System.Data.Mapping.Update.Internal.UpdateTranslator.RegisterReferentialConstraints(IEntityStateEntry stateEntry) at System.Data.Mapping.Update.Internal.UpdateTranslator.PullModifiedEntriesFromStateManager() at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands() at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter) at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache) at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options) at System.Data.Entity.Internal.InternalContext.SaveChanges() --- End of inner exception stack trace --- at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at LetLord.Migrations.Configuration.Seed(LetLordContext context) in c:\Users\Home\Desktop\LetLord\LetLord\Migrations\Configuration.cs:line 83

修改 - 解决方案:

实体应按照以下拉吉斯拉夫的回答,我的错误是在基地的很多副作用使得导航属性一流的,而不是派生类。

Entities should be as per Ladislav's answer below, my mistake was making navigation property on the many side of the base class, and not the derived class.

我的下一个错误是订购我的种子()法的实体。我已经添加了下面,他们应该是什么样的,这与加入协会的实体时尤其适用。

My next error was ordering of entities in my Seed() method. I've added below what they should be like, this applies especially when adding entities with associations.

    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<ResidentialProperty>()
            var landlords = new List<Landlord>
        {
            // landlord 1
            new Landlord { UserName="Frank",     FirstName="Frank",   LastName="O'Sullivan", Email="a@a.com", AccountType=(int)AccountType.Landlord, ResidentialProperties = new List<ResidentialProperty>() }

            // ...
        };
            landlords.ForEach(l => context.UserProfile.AddOrUpdate(l));
            context.SaveChanges();

            #endregion

            #region ResidentialProperties

            // then create a list of properties
            var residentialProperties = new List<ResidentialProperty>
        {
            // 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();
        }

当我试图运行更新数据库如上固定代码后,我遇到了这个错误:

When I tried to run update-database after fixing code as above, I ran into this error:

System.Data.Entity.Infrastructure.DbUpdateException:一个在更新的条目时发生错误。详情请参阅内部异常。 ---> System.Data.UpdateException:更新条目时发生错误。详情请参阅内部异常。 ---> System.Data.SqlClient.SqlException:INSERT语句冲突与外键约束FK_dbo.ResidentialProperty_dbo.Landlord_UserId。冲突发生于数据库C:\USERS\HOME\DESKTOP\LETLORD\LETLORD\APP_DATA\LETLORD.MDF,表dbo.Landlord,列用户ID。
语句已终止。

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.ResidentialProperty_dbo.Landlord_UserId". The conflict occurred in database "C:\USERS\HOME\DESKTOP\LETLORD\LETLORD\APP_DATA\LETLORD.MDF", table "dbo.Landlord", column 'UserId'. The statement has been terminated.

快速搜索我发现,正在导致这个错误后,(我认为)为已经有我的数据库中的数据。删除并重新创建数据库得到了解决这个,当我跑了种子()法再次被成功添加的数据。

After a quick search I found that this error was being caused (I think) as there was already data in my database. Dropping and recreating the database got around this and when I ran the Seed() method again data was added successfully.

推荐答案

如果楼主可以有多个属性和属性可以有<击>多个一个房东的模型应该是这样的:

If Landlord can have multiple properties and property can have multiple one landlord the model should look like:

[Table("Landlord")]
public class Landlord : UserProfile
{
    // A Landlord can have many ResidentialProperties
    public virtual ICollection<ResidentialProperty> 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; } 
}

这篇关于实体框架/代码首先/表每个类型继承 - 实现一个派生类和具体类之间是一个一对多关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆