我决定将实体框架核心用于我的Web API。我对一对多关系有意见。假设我们有Person
和PersonAddress
实体。实体作为一对多关系而相关。
public class Person
{
public int Id { get; set;}
public string Name { get; set;}
//Navigation property
public ICollection<PersonAddress> Addresses { get; set;}
}
public class PersonAddress
{
public int Id { get; set;}
public string Street { get; set;}
public int PersonId { get; set;}
//Navigation property
public Person Person {get;set;}
}
我在DbContext OnModelCreating
方法中配置了如下的实体
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PersonAddress>()
.HasOne(x => x.Person)
.WithMany(x => x.PersonAddresses)
.IsRequired(true)
.HasForeignKey(x => x.PersonId);
}
问题是,当我尝试获取包含Person
的PersonAddress
实体框架时,创建了带有左联接的查询。但我想创建内部联接。我的代码和查询是这样的:
var result = _dbContext.Persons.
.Include(x => x.PersonAddresses)
.ToList();
SELECT `l`.`*
FROM `Person` AS `l`
LEFT JOIN
`PersonAddresses` AS `l0`
ON `l`.`Id` = `t`.`PersonId`
我想了很多办法来解决这个问题,但都没有解决。有人面临这个问题吗?我该如何解决?
我使用Microsoft.EntityFrameworkCore 5.0.5版本
实体框架创建了带有左联接的查询。
它是关系数据库概念的基础。没有办法通过数据库约束来强制要求Person
至少有一个PersonAddress
。(除非你想扭转一个地址的关联,但这是另一个有自己问题的故事(。
映射API也没有任何正式的指令来映射1:1..n关系,这需要在保存数据时进行客户端验证。
英孚唯一能做的就是:简单地把你的要求退回去。你问_dbContext.Persons
,所以你得到了所有。Include
并没有说明你只想要有地址的人。它告诉您希望包含其地址(0..n(的所有人。
如何解决它?
- 添加谓词:
_dbContext.Persons.
.Where(p => p.PersonAddresses.Any())
.Include(x => x.PersonAddresses)
.ToList()
它通过OUTER JOIN
+WHERE
获得正确的数据,但不如内部联接。
- 在内存中手动写入内部联接和组
var result = (
from p in _dbContext.Persons
join pa in _dbContext.Addresses on p.Id equals pa.PersonId
select new { p, pa }
).AsEnumerable()
.GroupBy(r => r.p)
.Select(r => r.Key);
这将创建一个具有内部联接的查询,但这当然很麻烦。切换到内存(或客户端评估(是必要的,因为EF无法转换GroupBy
。
这个问题让我提出了一个IncludeInner
方法作为EF的特征要求。