首页 > 解决方案 > LINQ:一次查询两个表

问题描述

一个简单的实体框架 DbContext:

class SchoolDbContext : DbContext
{
    public DbSet<Teacher> Teachers {get; set;}
    public DbSet<Student> Students {get; set;}
}

要求给我教师人数和学生人数。

或者,更具挑战性:“给我所有老师的名字,给我所有学生的生日”

通常需要两次查询才能做到这一点。根据以下答案,可以在一个查询中使用 SQL 执行此操作:

答案是这样的:

SELECT id, startdate, enddate , '-' AS point_id 
FROM sarcshiftcentertable 
UNION
SELECT id, startdate, enddate, point_id 
FROM sarcshiftpointtable 

但是有可能在一个查询中使用 LINQ 做类似的事情吗?

答案将我指向Queryable.Union的方向。但是,此函数要求两个集合具有相同的输入类型。

所以我应该在联合之前选择一些共同点,在这种情况下是object

var result = dbContext.Teachers.Select(teacher => teacher.Name).Cast<object>()
    .Union(dbContext.Students.Select(student => student.BirthDay).Cast<object>())
    // TODO select?

现在序列中的每个 DateTime 都是学生的生日。每个字符串都是一个教师姓名。

另一种可能性是选择一个新类:

var result = dbContext.Teachers.Select(teacher => new
{
    TeacherName = teacher.Name,
    StudentBirthDay = null,
})
.Union(dbContext.Students.Select(student => new
{
     TeacherName = null,
     StudentBirthDay = student.BirthDay,
}))
// TODO: select?

到现在为止,我可以通过检查其他属性是否等于 null 来检测 Item 是 TeacherName 还是 StudentBirthDay。

但如何继续?我如何获得一个对象,例如:

new
{
    TeacherNames = ...
    StudentBirthdays = ...
}

或者

new
{
    TeacherCount = ...
    StudentCount = ...
}

标签: entity-frameworklinq

解决方案


使用异步方法,这可能是一件容易的事,而且可能更有效

async Task<IEnumerable<string>> GetTeacherNames()
{
    using (var context = CreateContext(fromConfiguration))
    {
        return await context.Teachers.Select(teacher => teacher.Name).ToListAsync();
    }
}

async Task<IEnumerable<DateTime>> GetStudentsBirthdays()
{
    using (var context = CreateContext(fromConfiguration))
    {
        return await context.Students.Select(student => student.BirthDay).ToListAsync();
    }
}

用法

var teacherTask = GetTeacherNames();
var studentsTask = GetStudentsBirthdays();

await Task.WhenAll(teacherTask, studentsTask);

var allTeacherNames = teacherTask.Result;
var allStudentsBirthdays = studentsTask.Result;

例如,如果教师查询需要 2 秒,学生查询需要 3 秒,则两个异步查询大约需要 3 秒。


推荐阅读