我们的目标是使用Entity Framework Core和.Include(...)
扩展方法查询数据库,以返回具有子项的对象集合,其中一些子项将为null。
我们有一个带有C#model Project 的表 Projects 和一个带有C#model Location 的表 Locations 。
每个 Project 都有一个或零个 Location 对象,对象如下所示:
public class Project
{
public string LocationId { get; set; }
public Location Location { get; set; }
}
public class Location
{
public string LocationId { get; set; }
}
数据库设置如下所示:
modelBuilder.Entity<Location>(entity =>
{
entity.HasKey(location => location.LocationId);
entity.ToTable("Locations");
});
modelBuilder.Entity<Project>(entity =>
{
entity.HasOne(project => project.Location).WithMany()
.HasForeignKey(x => x.LocationId);
entity.ToTable("Projects");
});
我们创建的查询是:
var projects = dbContext.Projects.Include(x => x.Location);
当我们期待 LEFT OUTER JOIN 时,EF生成的SQL包含 LEFT JOIN :
SELECT [project].[LocationId]
FROM [Projects] AS [project]
LEFT JOIN [Locations] AS [c] ON [project].[LocationId] = [c].[LocationId]
结果是只返回带有位置的项目。我们想要所有项目及其位置。
从this link我知道.Include(...)
根据外键的可为空性决定执行LEFT JOIN或LEFT OUTER JOIN:
Code First根据外键的可为空性推断出关系的多样性。如果属性可以为空,那么关系将被注册为可选。
由于事情并非如此,因此缺少一些东西。
无论是否填充其位置,都需要进行哪些修改才能返回所有项目?
谢谢!
答案 0 :(得分:2)
您可以在DefaultIfEmpty()
之后使用Include()
方法。
例如:
var projects = dbContext.Projects.Include(x => x.Location).DefaultIfEmpty()...;
答案 1 :(得分:0)
在T-SQL中,左连接和左外连接是相同的。外键字是可选的。您提供的查询将返回所有产品,无论他们是否有位置。测试一下,看看。
有关详细信息,请参阅:LEFT JOIN vs. LEFT OUTER JOIN in SQL Server
答案 2 :(得分:0)
我遇到了这种情况,除了生成的SQL是:
INNER JOIN [Blah.[Table] AS [x.Child] ON [x].[ChildId] = [x.Child].[Id]
这确实导致了问题,而问题LEFT JOIN
会没问题(正如其他人指出的那样)。
那么为什么会这样呢?我的ChildId
是Guid
,我确保将其设为Guid?
,因为可空性使其成为可选项。
我接下来尝试将.IsRequired(false)
添加到ChildId
的映射中。这给出了一个错误,告诉我实际问题是什么:我还在主键中包含ChildId
(不必要)。
从主键中删除它会导致查询更改为LEFT JOIN
,一切都很好。
答案 3 :(得分:-2)
尝试将 entity.HasOne(project =&gt; project.Location).WithMany()更改为 entity.HasOptional(project =&gt; project.Location).WithMany()强>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure Student & StudentAddress entity
modelBuilder.Entity<Student>()
.HasOptional(s => s.Address) // Mark Address property optional in Student entity
.WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student
}
检查此链接configure-one-to-one-relationship-in-code-first或 entity_framework-navigation_property_basics_with_code_first