如何解决如何在 EF6 中正确应用 1 对 1 的关系
所以我想将一个表的 1 比 1 关系应用到另一个表,每个表都有导航属性,外键至少可以在其中一个模型上访问。
让我们假设这个例子
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
modelBuilder.Entity<User>().HasOptional<Contact>(u=> u.Contact)
.Withrequired(c => c.User).Map(m => m.MapKey("ContactId")).
类似于此堆栈溢出问题中使用的相同示例:
EF Code First - 1-to-1 Optional Relationship
问题是它给出了一个错误,指出已经定义了属性名称“ContactId”。
但我想在数据库和模型上都定义这个外部属性,以便我可以使用例如 linq:
this.dbContextProvider.CurrentContext.User.SingleOrDefault(src => src.ContactId == contactId);
或者这是可以接受的还是非常低效的:
this.dbContextProvider.CurrentContext.User.SingleOrDefault(src => src.Contact.Id == contactId);
解决方法
正确模型(即没有明确的 User.ContactId
属性)的缺点是实际上它仍然是 1:n 关系。数据库不强制执行 1:1。这只是一个FK。在 EF6 中建立真正的、由数据库强制执行的 1:1 关联的唯一方法是,依赖实体(此处:User)具有一个主键,该主键也是主体实体(Contact)的外键:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
//public int ContactId { get; set; } <= removed
public virtual Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
还有:
modelBuilder.Entity<User>()
.HasRequired<Contact>(u => u.Contact)
.WithOptional(c => c.User);
这会生成以下数据库架构:
CREATE TABLE [dbo].[Users] (
[Id] [int] NOT NULL,[Username] [nvarchar](max),CONSTRAINT [PK_dbo.Users] PRIMARY KEY ([Id])
)
CREATE TABLE [dbo].[Contacts] (
[ID] [int] NOT NULL IDENTITY,[Name] [nvarchar](max),CONSTRAINT [PK_dbo.Contacts] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_Id] ON [dbo].[Users]([Id])
ALTER TABLE [dbo].[Users] ADD CONSTRAINT [FK_dbo.Users_dbo.Contacts_Id]
FOREIGN KEY ([Id]) REFERENCES [dbo].[Contacts] ([ID])
对于查询,在像 context.Users.Where(u => u.Contact.ID == 4)
这样的查询中,EF6 会注意到没有请求 Contact
字段,并且会将 FK 短路到 User.Id
,即没有连接。但当然,在这种设置中,您也可以使用 context.Users.Where(u => u.Id == 4)
。
在 EF 核心中,可以通过以下映射使用带有 User.ContactId
的模型:
modelBuilder.Entity<User>()
.HasOne(u => u.Contact)
.WithOne(c => c.User)
.HasForeignKey<User>(u => u.ContactId);
EF 内核足够智能,可以在 User.ContactId
上创建唯一索引,因此这是一个数据库强制执行的与单独 FK 的 1:1 关联。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。