使用 EF7 映射一对零或一
Posted
技术标签:
【中文标题】使用 EF7 映射一对零或一【英文标题】:Mapping One-to-Zero-or-One with EF7 【发布时间】:2016-07-30 05:27:32 【问题描述】:我目前正在清理一个相当大的数据库。部分数据库具有一对零或一映射的关系。具体来说:
User -> UserSettings
并非所有用户都有用户设置,但没有用户就不能存在用户设置。不幸的是,这些表已经存在。 User
有一个 PK ID。 UserSettings
有一个 PK ID 和一个列 User_Id_Fk
,此时它不是真正的 FK(没有定义关系)。
我正在修复这个问题,并且已经通过 SQL 从数据库的角度进行了修复,并通过测试进行了确认。 (添加了 FK 约束。在 User_Id_Fk
上添加了唯一约束。)这一切都是在 UserSettings
表上完成的。 (注意:我这里没有使用EF Migrations,此时我必须手动编写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;
我真的没有这个选项,因为数据库正在用于我目前无法控制的其他应用程序。那么,我被困在这里了吗?我是否只需要维护一个 1:many 映射(现在可能发生,尽管它还没有)并且没有适当的 1:0..1 映射约束?
更新
看看下面 octavioccl 的答案,我尝试了一下,但没有成功。但是,我随后从UserSettings
的映射中删除了User
(但我离开了UserId
)。据我所知,一切似乎都有效。然而,我真的很困惑这里发生了什么,如果这甚至是正确的答案,或者我只是走运。
【问题讨论】:
【参考方案1】:删除数据注释并尝试以下配置:
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);
来自EF Core documentation:
配置外键时需要指定依赖 实体类型 - 注意提供给
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;
【讨论】:
感谢您的回复。不幸的是,没有去。我对您的回答感到有些困惑,即用户应该只有零个或一个 UserSetting。我不明白您的解决方案如何实现这一目标。 (这超出了我仍然收到相同错误的事实。)您能否提供澄清?谢谢! 我现在看到了您的更新,我认为它有效,因为 EF 现在将您的关系视为一对多而不是一对一。当您在相关实体之间仅声明一个导航属性时,EF 默认创建一对多,我也对您当前模型的工作方式感到困惑,因为如果您在UserSettings
表中有 FK 列,以防 EF 看到一对多,集合导航属性应在User
中声明,而不是引用导航属性。确实很迷茫,让我再想一想,如果我找到合理的东西我会告诉你
是的,我同意这种安排有点奇怪。最后,User
应该只有一个或没有UserSettings
。每个UserSettings
都应该附加到一个用户。 (这是通过对UserSettings
的 FK 的唯一约束来强制执行的。)我不确定如何在 EF 中正确建模这种关系。感谢您的帮助。
哈哈,所以,我刚刚从你那里找到了这个答案(原则/依赖)。它成功了(我认为)。我不认为我想做的事情是可能的,否则。 ***.com/questions/28499126/…以上是关于使用 EF7 映射一对零或一的主要内容,如果未能解决你的问题,请参考以下文章
EF 代码优先 - 配置一对零或一关系,无需共享 PK/FK