我喜欢尽可能使用扩展方法编写查询。所以以下是一个适合我的查询:
int studentId =
(
from u in db.Users
.FromOrganisation(org.Id)
.IsStudent()
.IsActive()
where u.ExtId == dto.StudentExtId
select u.Id
).FirstOrDefault();
扩展方法如下:
public static IQueryable<User> IsStudent(this IQueryable<User> u)
{
return u.Where(x => x.Type == (int)UserTypes.Student);
}
但是,当我在子查询中使用扩展方法时,我收到以下消息:
LINQ to Entities无法识别方法&#39; System.Linq.IQueryable`1 [eNotify.Domain.Models.User] IsActive(System.Linq.IQueryable`1 [eNotify.Domain.Models.User]) &#39;方法,并且此方法无法转换为商店表达式。
以下是导致该消息的查询:
var vm = from o in db.Organisations
select new StaffStudentVm
{
StudentId = (
from u in db.Users
.FromOrganisation(org.Id)
.IsStudent()
.IsActive()
where u.ExtId == dto.StudentExtId
select u.Id
).FirstOrDefault(),
StaffId = (
from u in db.Users
.FromOrganisation(org.Id)
.IsStaff()
.IsActive()
where u.ExtId == dto.StaffExtId
select u.Id
).FirstOrDefault()
};
return vm.FirstOrDefault();
我做错了什么?
更新 Alexander Derck发布了一个运行良好的解决方案,但并不像原始问题查询那样好。我和EF团队一起提出了这个问题,经过调查他们想出了一个更优雅的解决方案。我在下面发布了接受的答案。
答案 0 :(得分:1)
我最终在GitHub上使用Entity Framework团队提出了这个问题。您可以在此处查看该主题,并详细说明其发生的原因:
https://github.com/aspnet/EntityFramework6/issues/98
似乎已经提出将其纳入EF 6.2,但在此之前,建议采用非常优雅的解决方案。你可以在线程中阅读它,但我已将其复制到此处以供快速参考。
这是原始查询(由于在子查询中使用了IQueryable扩展方法而发生错误):
var vm = from o in db.Organisations
select new StaffStudentVm
{
StudentId = (
from u in db.Users
.FromOrganisation(org.Id)
.IsStudent()
.IsActive()
where u.ExtId == dto.StudentExtId
select u.Id
).FirstOrDefault(),
StaffId = (
from u in db.Users
.FromOrganisation(org.Id)
.IsStaff()
.IsActive()
where u.ExtId == dto.StaffExtId
select u.Id
).FirstOrDefault()
};
return vm.FirstOrDefault();
以下是如何编写它以便不会发生错误:
var stuList = db.Users.FromOrganisation(org.Id).IsStudent().IsActive();
var staffList = db.Users.FromOrganisation(org.Id).IsStaff().IsActive();
var vm = from o in db.Organisations
select new StaffStudentVm
{
StudentId = (
from u in stuList
where u.ExtId == dto.StudentExtId
select u.Id
).FirstOrDefault(),
StaffId = (
from u in staffList
where u.ExtId == dto.StaffExtId
select u.Id
).FirstOrDefault()
};
return vm.FirstOrDefault();
我可以确认这种风格仍然只会导致数据库往返一次。将查询分解为多个语句实际上也提高了许多地方的可读性。
答案 1 :(得分:0)
您可以使用静态类为User
模型创建一个部分类:
partial class User
{
public static class Q
{
public static Expression<Func<User,bool>> IsStudent
{
return x => x.Type == (int)UserTypes.Student;
}
}
}
然后您的查询将如下所示:
var vm = from o in db.Organisations
select new StaffStudentVm
{
StudentId = (
from u in db.Users
.FromOrganisation(org.Id)
.Where(User.Q.IsStudent)
.IsActive()
where u.ExtId == dto.StudentExtId
select u.Id
).FirstOrDefault(),
StaffId = (
from u in db.Users
.FromOrganisation(org.Id)
.IsStaff()
.IsActive()
where u.ExtId == dto.StaffExtId
select u.Id
).FirstOrDefault()
};
它不如扩展方法那么优雅,但它应该做我认为的技巧......