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

时间:2013-10-15 08:09:13

标签: c# entity-framework ef-code-first fluent-interface

我试图让1到0..1映射在Entity Framework Code First中工作,但不断收到错误: ReferentialConstraint中的依赖属性映射到存储生成的列。专栏:'Id'。

我有一个带有所需位置的MainLocation,但由于Locations可以有多个子Locations,因此Location对象中不需要MainLocation。

MainLocation与MainLocationAddress具有类似的关系,但这是1对1的关系,而这又构成了相同的db表。

ER模型应如下所示: enter image description here

我的实体看起来像这样:

[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; }
}

我在DbContext类的OnModelCreating中配置了关联:

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

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

PS!位置上的MainLocation属性受到保护,因为不应直接访问它。相反,我有一个服务层,它从位置获取值或从ParentLocation获取继承的值。我试图将其更改为公开,看看它是否对我得到的错误做了任何更改。

虽然我能够将.WithOptional()扩展为.WithOptional(x =&gt; x.MainLocation),但所述错误仍然没有变化。

3 个答案:

答案 0 :(得分:1)

我在两个实体Person和User之间实现了1:0-1的关联。要求,用户必须只有一个人;而某人可能与用户有关,也可能没有。

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; }
}

按如下所示定义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 }));

     }

}

将以下行放在DbContext.OnModelCreating方法中。

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

运行Add-Migration命令,您将在DbMigration,Up方法中获得类似以下内容的内容。进行如下更改。

        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)

按如下方式修改Down()方法。

更改

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

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

更改

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

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

运行针对此迁移的Update-Database命令。生成的Users和People表将在PersonId外键上具有一对一关联。

答案 1 :(得分:0)

我已经意识到这在EF中是不可能实现的(1到0..1关联)。

我已经在我们的解决方案中通过让所有子位置都引用了主要位置来解决它。我仍然可以通过查找没有父位置的位置来获得最高组织。所以,虽然它不是我们想要的,但它并没有打破我们的商业模式。

答案 2 :(得分:0)

此方案在Update-Database上运行正常,因为所需的数据库结构显示了User表和People表之间的一对一关系。但是,由于某种原因,尝试查询Users表。

我通过删除PersonId属性来更改User类。

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

UserConfiguration类变为:

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

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

     }

}

Add-Migration产生:        CREATETABLE(             &#34; dbo.Users&#34 ;,             c =&gt;新                 {                     Id = c.String(nullable:false,maxLength:128),                     Person_PersonId = c.Int(nullable:false),//保持这个                 })             .PrimaryKey(t =&gt; t.UserId)             .ForeignKey(&#34; dbo.People&#34;,t =&gt; t.Person_PersonId)             .Index(t =&gt; t._Person_PersonId); //更改为.Index(t =&gt; t._Person_PersonId,unique:true);

Update-Database生成具有一对一关系的User和People表,框架使用自己生成的Person_PersonId列。