我对 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/