简体   繁体   English

在实体框架代码优先中将1映射到0..1

[英]Mapping 1 to 0..1 in Entity Framework Code First

I am trying to get 1 to 0..1 mapping to work in Entity Framework Code First, but keep getting the error: A dependent property in a ReferentialConstraint is mapped to a store-generated column. 我正在尝试获取1到0..1的映射以在Entity Framework Code First中工作,但始终收到错误: ReferentialConstraint中的一个依赖属性被映射到存储生成的列。 Column: 'Id'. 列:“ Id”。

I have a MainLocation with a required Location, but as the Locations can have multiple child Locations, a MainLocation is not required in the Location object. 我有一个带有必需位置的MainLocation,但是由于Locations可以有多个子Location,因此在Location对象中不需要MainLocation。

The MainLocation has a similar relation to MainLocationAddress, but this is a 1 to 1 relation which in turn make up the same db table. MainLocation与MainLocationAddress具有相似的关系,但这是一对一的关系,进而构成了相同的db表。

The ER model should look like this: ER模型应如下所示: 在此处输入图片说明

My entities look like this: 我的实体看起来像这样:

[Table("MainLocation")]
public class MainLocation : IEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public virtual MainLocationAddress Address { get; set; }
    [Required]
    public virtual Location Location { get; set; }
}

[Table("MainLocation")]
public class MainLocationAddress : BaseAddress
{
    [Key, ForeignKey("MainLocation")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }
    public virtual MainLocation MainLocation { get; set; }
}

public class Location : IEntity
{
    public int Id { get; set; }
    public virtual Location ParentLocation { get; set; }
    public virtual ICollection<Location> ChildLocations { get; set; }
    protected virtual MainLocation MainLocation { get; set; }
    internal MainLocation GetMainLocation() { return this.MainLocation; }
    internal void SetMainLocation(MainLocation mainLocation) { MainLocation = mainLocation; }
}

I have configured the associations in OnModelCreating in my DbContext class: 我在DbContext类的OnModelCreating中配置了关联:

modelBuilder.Entity<MainLocation>()
            .HasRequired(x => x.Location)
            .WithOptional();

modelBuilder.Entity<MainLocation>()
            .HasRequired(x => x.Address)
            .WithRequiredPrincipal();

PS! PS! The MainLocation property on Location is protected because it should not be accessed directly. Location上的MainLocation属性受到保护,因为不应直接访问它。 Instead I have a service-layer which gets the value from the Location or the inherited value from a ParentLocation. 相反,我有一个服务层,该服务层从Location获取值或从ParentLocation继承值。 I have tried to change it to public, to see if it made any changes regarding the error I'm getting. 我试图将其更改为公开,以查看它是否对我遇到的错误进行了任何更改。

Although I was able to extend .WithOptional() to .WithOptional(x => x.MainLocation), there were still no changes in the stated error. 尽管我可以将.WithOptional()扩展到.WithOptional(x => x.MainLocation),但是在声明的错误中仍然没有任何变化。

I have achieved a 1:0-1 association between two entities, Person and User. 我已经在个人和用户这两个实体之间实现了1:0-1关联。 The requirement, a User must have one and only one Person; 要求,一个用户必须只有一个人; while a Person may or may not be associated with a User. 而一个人可能会或可能不会与用户相关联。

public class Person
{
    public int PersonId { get; set; }
    public virtual User User { get; set; }
}

public class User
{
    public int UserId { get; set; }
    public int PersonId { get; set; }
    public virtual Person Person { get; set; }
}

Define EntityTypeConfiguration classes as follows and include them in the DbContext OnModelCreating method. 如下定义EntityTypeConfiguration类,并将它们包括在DbContext OnModelCreating方法中。

public class PersonConfiguration : EntityTypeConfiguration<Person>
{
    public PersonConfiguration()
    {
        ToTable("People");
        HasKey(p => p.PersonId);
        Property(p => p.PersonId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        HasOptional(p => p.User).WithRequired(u => u.Person); // User is option here but
                                                              // Person is required in User
    }

}

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {

        ToTable("Users");
        HasKey(u => u.UserId);
        Property(u => u.UserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        // Create a unique index in the Users table on PersonId
        Property(u => u.PersonId).IsRequired().HasColumnAnnotation("Index",
            new IndexAnnotation(new IndexAttribute("IX_PersonId") { IsUnique = true }));

     }

}

Put the following lines in the DbContext.OnModelCreating method. 将以下行放入DbContext.OnModelCreating方法中。

        modelBuilder.Configurations.Add(new PersonConfiguration());
        modelBuilder.Configurations.Add(new UserConfiguration());

Run an Add-Migration command and you will get something like the following in the DbMigration,Up method. 运行一个Add-Migration命令,您将在DbMigration,Up方法中得到类似以下的内容。 Make changes as follows. 进行如下更改。

        CreateTable(
            "dbo.Users",
            c => new
                {
                    Id = c.String(nullable: false, maxLength: 128),
                    PersonId = c.Int(nullable: false),
                    Person_PersonId = c.Int(nullable: false), // Delete this
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.People", t => t.Person_PersonId) // change to .ForeignKey("dbo.People", t => t.PersonId)
            .Index(t => t.PersonId, unique: true)  // append a ';'
            .Index(t => t._Person_PersonId); // Delete this

        CreateTable(
            "dbo.People",
            c => new
                {
                    PersonId = c.Int(nullable: false, identity: true),
               })
            .PrimaryKey(t => t.PersonId)

Modify the Down() method as follows. 修改Down()方法,如下所示。

Change 更改

 DropForeignKey("dbo.Users", "Person_PersonId", "dbo.People");

to

 DropForeignKey("dbo.AppUsers", "PersonId", "dbo.People");

Change 更改

 DropIndex("dbo.AppUsers", new[] { "Person_PersonId" });

to

 DropIndex("dbo.AppUsers", new[] { "PersonId" });

Run the Update-Database command targeting this migration. 运行针对此迁移的Update-Database命令。 The resulting Users and People tables will have a one-to-one association on the PersonId foreign key. 结果的Users和People表将在PersonId外键上具有一对一的关联。

I have come to realize that this is not possible to accomplish in EF as it is at the moment (the 1 to 0..1 association). 我已经意识到,这不可能在EF中完成,因为目前是这样(从1到0..1的关联)。

I have solved it in our solution by letting all the child locations have a reference to the main location. 我在解决方案中解决了这一问题,方法是让所有子位置都引用主位置。 I can still get the top organization by looking for a location with no parent location. 我仍然可以通过查找没有父级位置的位置来获得顶级组织。 So, although it's not quite what we wanted, it doesn't break our business-model. 因此,尽管这不是我们想要的,但它并没有破坏我们的业务模型。

This scenario works fine on the Update-Database in that the desired database structure showing a one-to-one relationship between the User and People tables. 此方案在Update-Database上运行良好,因为所需的数据库结构显示了User和People表之间的一对一关系。 However, for some reason attempts to query the Users table. 但是,由于某种原因尝试查询Users表。

I changed the User class by removing the PersonId property. 我通过删除PersonId属性更改了User类。

public class User
{
    public int UserId { get; set; }
    public virtual Person Person { get; set; }
}

The UserConfiguration class becomes: UserConfiguration类变为:

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {

        ToTable("Users");
        HasKey(u => u.UserId);
        Property(u => u.UserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

     }

}

The Add-Migration produces: CreateTable( "dbo.Users", c => new { Id = c.String(nullable: false, maxLength: 128), Person_PersonId = c.Int(nullable: false), // Keep this }) .PrimaryKey(t => t.UserId) .ForeignKey("dbo.People", t => t.Person_PersonId) .Index(t => t._Person_PersonId); Add-Migration产生:CreateTable(“ dbo.Users”,c => new {ID = c.String(nullable:false,maxLength:128),Person_PersonId = c.Int(nullable:false),//保留此} ).PrimaryKey(t => t.UserId).ForeignKey(“ dbo.People”,t => t.Person_PersonId).Index(t => t._Person_PersonId); // Change to .Index(t => t._Person_PersonId, unique: true); //更改为.Index(t => t._Person_PersonId,unique:true);

The Update-Database produces User and People table with one-to-one relationship and the framework uses its own generated Person_PersonId column. Update-Database生成具有一对一关系的User和People表,并且框架使用其自己生成的Person_PersonId列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM