我从 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.