1

我的 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成为一个可选属性UserProfileUserSerialNumber添加到时自动设置UserProfile

4

1 回答 1

4

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

因此,外键被添加到依赖项中,在像您这里这样的一对零对一的情况下,它是所需导航属性的结尾:您的SerialNumber模型。这意味着要真正创建一对一而不是一对多,您的键SerialNumber需要是User_UserId(自动生成的外键列,因为您没有手动指定外键属性)。要以这种方式进行设置,您的模型将如下所示:

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

    ...
}

或者使用 Fluent API:

modelBuilder.Entity<SerialNumber>()
    .HasRequired(m => m.User)
    .WithOptional(m => m.Serial);

(您需要省略[Key]数据注释,以便 EF 可以制作外键,它们是表的主键。)

但是,这使您对您的Code财产没有唯一的限制。你当然可以在你的表上手动设置这个约束,或者如果你不使用自动迁移,你可以改变你的迁移来创建约束:

CreateIndex("dbo.SerialNumbers", "Code", unique: true);

这里的问题是实体框架不会为您处理唯一验证。因此,您需要在您的代码中手动维护完整性(即,尝试SerialNumber使用Code您将要保存的 查找 a,并且只有在您没有从查询中得到任何返回时才保存它)。

这有点痛苦,我知道,但就目前而言,这就是你所能做的。希望 EF 最终会在未来的版本中解决唯一性问题。

于 2013-04-04T01:55:34.513 回答