【发布时间】:2017-11-27 09:57:54
【问题描述】:
我在通过实体框架/Linq-to-Entities 访问数据库的存储库中有许多复杂的查询。通常,这些查询是由许多重要的子查询组成的。一般来说,子查询用于不同的存储库方法以及其他域逻辑。将它们放在存储库层外部但可以访问它们是有意义的。
因此,我想使用规范模式来封装其中一些子查询。
我正在为我的规范类使用基类:
public abstract class Specification<T> : ISpecification<T> where T : class
{
public abstract Expression<Func<T, bool>> ToExpression();
public virtual bool IsSatisfiedBy(T candidate)
{
var predicate = ToExpression().Compile();
return predicate(candidate);
}
public Specification<T> And(Specification<T> specification)
{
return new AndSpecification<T>(this, specification);
}
public Specification<T> Or(Specification<T> specification)
{
return new OrSpecification<T>(this, specification);
}
}
示例规范可能如下所示:
public class IsAssignmentSetForStudentSpecification : Specification<Assignment>
{
private readonly Student _student;
public IsAssignmentSetForStudentSpecification(Student student)
{
_student = student;
}
public override Expression<Func<Assignment, bool>> ToExpression()
{
return x => !x.Exclusions.Contains(_student) &&
(
_student.Classes.Select(c => c.Subject).Intersect(x.Subjects).Any() ||
x.TutorGroups.Contains(_student.TutorGroup) ||
x.Houses.Contains(_student.House) ||
x.YearGroups.Contains(_student.YearGroup) ||
x.Students.Contains(_student)
);
}
}
如您所见,我不希望在每个存储库查询中编写此类代码。
作为存储库查询方法(使用各种规范)可能如下所示:
public ICollection<Assignment> GetAssignmentsDueInForStudent(Student student, DateRange dateRange)
{
var isAssignmentAssignedToStudent = new IsAssignmentSetForStudentSpecification(student);
var isAssignmentDueInDateRange = new IsAssignmentDueInDateRangeSpecification(dateRange);
var hasStudentCompletedAssignment = new HasStudentCompletedAssignmentSpecification(student);
return (from a in Set
.Where(x => isAssignmentAssignedToStudent
.And(isAssignmentDueInDateRange).IsSatisfiedBy(x))
.Where(x => !hasStudentCompletedAssignment.IsSatisfiedBy(x))
select a)
.ToList(queryOptions);
}
在上述方法中,Set 是一个IDbSet<>
不幸的是,当我运行查询时,我收到以下错误:
LINQ to Entities 无法识别方法 'Boolean IsSatisfiedBy(Beehive.Domain.Planner.Assignments.Assignment)' 方法,并且该方法无法转换为存储表达式。
我该如何解决这个问题?
【问题讨论】:
-
您应该使用
ToExpression方法,大概是在查询表达式树之外。例如,Set.Where(isAssignmentAssignedToStudent.And(isAssignmentDueInDateRange).ToExpression()).ToList()。但是表达式也应该是 EF 兼容的,例如x.Exclusions.Contains(_student)和_student.Classes.Select(c => c.Subject).Intersect(x.Subjects).Any()很可能不会工作。这是一个艰难的话题。
标签: c# .net entity-framework linq