微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 EF6 中正确应用 1 对 1 的关系

如何解决如何在 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 举报,一经查实,本站将立刻删除。