一对一映射问题

时间:2013-04-04 01:12:18

标签: c# asp.net-mvc ef-code-first entity-framework-5

我的SQL理解非常基础,我来自NHibernate的世界,所以我对这个问题感到很困惑......

我有两个班级:

public class UserProfile
{
    public UserProfile() { }

    [Key]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public SerialNumber Serial { get; set; }
    // Other properties
}

public class SerialNumber
{
    public SerialNumber() 
    {
        // My code that creates a unique Code
    }

    [Key]
    public string Code { get; set; }
    public UserProfile User { get; set; }

    // Other Properties
}

我有这个

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Other modelBuilder stuff

    modelBuilder.Entity<UserProfile>()
        .HasOptional(s => s.Serial)
        .WithRequired(u => u.User);
}

运行Add-Migration后,我明白了:

public override void Up()
{
    DropForeignKey("dbo.UserProfile", "Serial_Code", "dbo.SerialNumbers");
    DropIndex("dbo.UserProfile", new[] { "Serial_Code" });
    RenameColumn(table: "dbo.SerialNumbers", name: "Serial_Code", newName: "User_UserId");
    AddForeignKey("dbo.SerialNumbers", "User_UserId", "dbo.UserProfile", "UserId");
    CreateIndex("dbo.SerialNumbers", "User_UserId");
}

public override void Down()
{
    // Inverse of above
}

运行Update-Database后,我收到错误消息: "Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong."

我可以通过Add-Migration生成的代码告诉我出错了,因为我的db表甚至没有名称为"Serial_Code"的列

我需要Code成为我的Key,因为EntityFramework没有选项可以将列强制为Unique,除非使其成为密钥。

如何Serial成为UserProfile中的UserSerialNumber的可选属性,以便在UserProfile添加到{{1}}后自动设置?< / p>

1 个答案:

答案 0 :(得分:4)

默认情况下,在一对一关系中,Entity Framework要求依赖项上的外键也是主键。这可能是因为实体框架仅对主键设置了唯一约束(或者说,由于它是主键,因此存在唯一约束)。在数据库的级别上,一对一不映射到关系的两侧,即在两个表上都没有创建外键。当您考虑参照完整性如何工作时,这是有道理的:如果关系的一方被删除,则会导致另一方的数据库分离,导致一种无限循环。

因此,将外键添加到依赖项中,在此情况下,如果您具有所需的导航属性,则为{1}}模型。这意味着要真正创建一对一而不是一对多,SerialNumber上的密钥需要SerialNumber(自动生成的外键列,因为你没有不要手动指定外键属性。要以这种方式进行设置,您的模型将如下所示:

User_UserId

或使用Fluent API:

public class UserProfile
{
    [Key]
    public int UserId { get; set; }

    public SerialNumber Serial { get; set; }

    ...
}

public class SerialNumber
{
    [Key]
    [ForeignKey("User")]
    public int UserId { get; set; }

    public UserProfile User { get; set; }

    ...
}

(您需要取消modelBuilder.Entity<SerialNumber>() .HasRequired(m => m.User) .WithOptional(m => m.Serial); 数据注释,以便EF可以创建外键,它们是表的主键。)

但是,这使您在[Key]属性上没有唯一约束。您当然可以在表上手动设置此约束,或者如果您不使用自动迁移,则可以更改迁移以创建约束:

Code

这里的问题是Entity Framework不会为您处理独特的验证。因此,您需要在代码中手动维护完整性(即,尝试使用您要保存的CreateIndex("dbo.SerialNumbers", "Code", unique: true); 查找SerialNumber,并且只有在您没有得到任何内容时才保存它从查询中回来)。

这是一种痛苦,我知道,但就目前而言,这就是你所能做的一切。希望EF能够在未来版本中最终解决其独特性。