c# - 一对一映射问题

标签 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 之后,我得到一个错误: “参数@objname 不明确或声明的@objtype (COLUMN) 错误。”

我可以通过 Add-Migration 生成的代码判断出问题,因为我的数据库表甚至没有名为 "Serial_Code" 的列

我需要 Code 作为我的 Key 因为 EntityFramework 没有选项来强制列是 Unique 除非让它一把 key 。

如何使 Serial 成为 UserProfile 的可选属性,并使 SerialNumber 中的 User 自动成为添加到 UserProfile 时设置?

最佳答案

默认情况下,在一对一关系中, 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);

这里的问题是 Entity Framework 不会为您处理唯一验证。因此,您需要在代码中手动维护完整性(即,尝试使用要保存的 Code 查找 SerialNumber,并且仅在以下情况下保存它你不会从查询中得到任何结果)。

这有点痛苦,我知道,但目前,您只能做这些。希望 EF 最终会在未来的版本中解决唯一性问题。

关于c# - 一对一映射问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15800935/

相关文章:

jquery - 如何使用 javascript 函数调用 MVC 中的 URL 操作?

c# - 如何在 Entity Framework Code First 中以编程方式使用迁移?

c# - Database.SetInitializer 中的 DropCreateDatabaseIfModelChanges

entity-framework - Entity Framework 6 代码优先 默认值

c# - 使用 MS Sync Framework 2.0,如何最好地处理相关表?

c# - 取消后台任务

c# - 是否可以在没有代码覆盖工具作为入口点的情况下收集代码覆盖数据?

C# CURL POST(内容类型,哈希键)

c# - 在 IIS 8 上运行应用程序时如何委派 Windows 身份验证 session ?

javascript - type=”number” 和基于文化的小数点分隔符的 html 标签输入