我从 Linq 查询表达式到基于方法的查询的转换有什么问题?
What's wrong with my translation from Linq Query Expression to Method-Based Query?
我有两个聚合根:学生和测试,每个学生可以有 0..1 个测试。我正在使用 EF Core 3.1 执行左外连接查询,以通过她自己的测试获取学生。由于学生的测试可能为空,并且 EF Core 不支持数据库 GroupJoin,因此我将查询写成这样:
var studentsWithTest = from o in dbContext.Students
join x in dbContext.Tests on o.TestId
equals x.Id into tests
from x in tests.DefaultIfEmpty()
select new {o.Student, Test = x};
有效。但是,我真正感兴趣的是执行相同功能的基于等效方法的查询。我试着把它翻译成这样:
var studentsWithTest = dbContext.Students.SelectMany(o =>
dbContext.Tests
.Where(x => x.Id == o.TestId).DefaultIfEmpty()
.Select(x => new {o.Student, Test = x}));
但此代码导致 运行 次异常:
Processing of the LINQ expression '(ProjectionBindingExpression:
Student)' by 'RelationalProjectionBindingExpressionVisitor' failed.
This may indicate either a bug or a limitation in EF Core. See
https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed
information.
这是否意味着我在翻译过程中有错误?你们能帮我弄清楚吗?谢谢
对于这个错误,错误信息中的link将是最好的解释。
要解决此问题,请将 ToList() 添加到 dbContext.Students
,如下所示:
var studentsWithTest = dbContext.Students.ToList().SelectMany(o =>
dbContext.Tests
.Where(x => x.Id == o.TestId).DefaultIfEmpty()
.Select(x => new {o.Student, Test = x}));
但是ef core中的one-to-one
关系,也可以用Include其实是最简单的方法,参考下面的写法:
public class Student
{
public int Id{ get; set; }
public string Name { get; set; }
public int? TestId{ get; set; }
public Test Test{ get; set; }
}
public class Test
{
public int Id{ get; set; }
public string Name { get; set; }
public Student Student { get; set; }
}
林克:
var studentsWithTest = dbContext.Students.Include(x => x.Tests)
.Select(x => new { x, Test = x.Tests });
更新
正如你评论所说,你可以试试这个代码:
var studentsWithTest = dbContext.Students
.SelectMany(o => dbContext.Tests.Where(x => x.Id == o.TestId).DefaultIfEmpty(), (o, x) => new
{
o.Student,
Test = x
});
也可以参考this.
我有两个聚合根:学生和测试,每个学生可以有 0..1 个测试。我正在使用 EF Core 3.1 执行左外连接查询,以通过她自己的测试获取学生。由于学生的测试可能为空,并且 EF Core 不支持数据库 GroupJoin,因此我将查询写成这样:
var studentsWithTest = from o in dbContext.Students
join x in dbContext.Tests on o.TestId
equals x.Id into tests
from x in tests.DefaultIfEmpty()
select new {o.Student, Test = x};
有效。但是,我真正感兴趣的是执行相同功能的基于等效方法的查询。我试着把它翻译成这样:
var studentsWithTest = dbContext.Students.SelectMany(o =>
dbContext.Tests
.Where(x => x.Id == o.TestId).DefaultIfEmpty()
.Select(x => new {o.Student, Test = x}));
但此代码导致 运行 次异常:
Processing of the LINQ expression '(ProjectionBindingExpression: Student)' by 'RelationalProjectionBindingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
这是否意味着我在翻译过程中有错误?你们能帮我弄清楚吗?谢谢
对于这个错误,错误信息中的link将是最好的解释。
要解决此问题,请将 ToList() 添加到 dbContext.Students
,如下所示:
var studentsWithTest = dbContext.Students.ToList().SelectMany(o =>
dbContext.Tests
.Where(x => x.Id == o.TestId).DefaultIfEmpty()
.Select(x => new {o.Student, Test = x}));
但是ef core中的one-to-one
关系,也可以用Include其实是最简单的方法,参考下面的写法:
public class Student
{
public int Id{ get; set; }
public string Name { get; set; }
public int? TestId{ get; set; }
public Test Test{ get; set; }
}
public class Test
{
public int Id{ get; set; }
public string Name { get; set; }
public Student Student { get; set; }
}
林克:
var studentsWithTest = dbContext.Students.Include(x => x.Tests)
.Select(x => new { x, Test = x.Tests });
更新
正如你评论所说,你可以试试这个代码:
var studentsWithTest = dbContext.Students
.SelectMany(o => dbContext.Tests.Where(x => x.Id == o.TestId).DefaultIfEmpty(), (o, x) => new
{
o.Student,
Test = x
});
也可以参考this.