所以我想在一个表到另一个表之间应用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码优先-1对1可选关系
问题是它给出了一个错误,说属性名'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)
。
InEF core它可以使用您的模型,与User.ContactId
,通过以下映射:
modelBuilder.Entity<User>()
.HasOne(u => u.Contact)
.WithOne(c => c.User)
.HasForeignKey<User>(u => u.ContactId);
EF core足够聪明,可以在User.ContactId
上创建一个唯一的索引,因此这是一个数据库强制的与单独FK的1:1关联。