我目前正在清理一个相当大的数据库。数据库的一部分具有一对一或零映射的关系。具体做法是:
User -> UserSettings
并非所有用户都有用户设置,但没有用户就无法存在用户设置。不幸的是,这些表已经存在。 User
有一个PK ID。 UserSettings
有一个PK ID和一列User_Id_Fk
,此时此列不是真正的FK(没有定义任何关系)。
我正在修复它,并且已经通过SQL从数据库角度完成了这一过程并且已通过测试确认。 (添加了FK约束。在User_Id_Fk
上添加了一个唯一约束。)这都是在UserSettings
表上完成的。 (注意:我这里没有使用EF迁移。我必须在此时手动编写SQL。)
但是,我现在需要连接现有应用程序以正确处理这个新映射。该应用程序使用ASP.NET Core 1.0和EF7。以下是现有数据模型的(缩短版)。
public class User
{
public int Id { get; set; }
public virtual UserSettings UserSettings { get; set; }
}
public class UserSettings
{
public int Id { get; set; }
[Column("User_Id_Fk")]
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
我也有这个Fluent Mapping:
builder.Entity<UserSettings>()
.HasOne(us => us.User)
.WithOne(u => u.User)
.IsRequired(false);
当我去运行应用程序并访问数据库中的这些项目时,我收到此错误,然后是一组隐藏的消息,这些消息没有直接与我的应用程序相关的信息。:
ArgumentNullException: Value cannot be null.
Parameter name: navigation
Microsoft.Data.Entity.Utilities.Check.NotNull[T] (Microsoft.Data.Entity.Utilities.T value, System.String parameterName) <0x10d28a650 + 0x00081> in <filename unknown>, line 0
经过研究,有人提到UserSettings类的ID必须与外键相同,如下所示:
public class UserSettings
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public virtual User User { get; set; }
}
我没有把它作为一个选项,因为DB正用于我此时无法控制的其他应用程序。那么,我被困在这里了吗?我是否只需要维护一个1:多的映射(现在可以发生,虽然它没有)并且对1:0..1映射没有适当的约束?
更新
看下面的octavioccl的答案,我尝试了没有任何成功。但是,我随后从User
中的映射中删除了UserSettings
(但我离开了UserId
)。就我所知,一切似乎都有效。我真的很困惑这里发生了什么,如果这是正确的答案,或者我只是幸运。
答案 0 :(得分:4)
删除数据注释并尝试使用以下配置:
builder.Entity<UserSettings>()
.Property(b => b.UserId)
.HasColumnName("User_Id_Fk");
builder.Entity<User>()
.HasOne(us => us.UserSettings)
.WithOne(u => u.User)
.HasForeignKey<UserSettings>(b => b.UserId);
配置外键时,需要指定依赖项 实体类型 - 注意提供给
HasForeignKey
的通用参数 在上面的列表中。在一对多的关系中,很明显 具有参考导航的实体是从属实体和一个实体 与集合是主要的。但事实并非如此 一对一的关系 - 因此需要明确定义它。
quoted link(Blog
- BlogImage
)中显示的示例与您要实现的内容几乎相同。
如果我上面显示的解决方案不起作用,那么您应该检查User_Id_Fk
列是否允许null
。如果是这种情况,请将FK属性类型更改为int?
:
public class UserSettings
{
public int Id { get; set; }
public int? UserId { get; set; }
public virtual User User { get; set; }
}