有人可以告诉我为什么我不能以这种方式从实体框架中的MS SQL数据库中选择新对象:
public static Expression<Func<LeaveDay, bool>> IsInDatesRange(DateTime startDate, DateTime endDate){
return ld => ld.StartDate <= endDate && ld.EndDate >= startDate;
}
this.ObjectContext.People.Select(p => new NewPeopleObject
{
Guid = p.Guid,
FirstName = p.FirstName,
LastName = p.LastName,
LeaveDays = p.CalendarData.LeaveDays.AsQueryable()
.Where(LeaveDayExpressions.IsInDatesRange(startDate, endDate))
.Select(ld => new LeaveDaySummary
{
StartDate = ld.StartDate,
EndDate = ld.EndDate,
})
})
没有AsQueryable()
我无法编译应用程序,因为LeaveDayExpressions.IsInDatesRange
是静态表达式。我尝试只将Func传递给Where
子句,但它会抛出内部.NET Framework数据提供程序错误1025.使用表达式和AsQueryable
LeaveDays
我得到此异常:
代码无法访问
人是ObjectSet
集合,其中一个CalendarData
上有一个People
个对象,CalendarData
EntityCollection
集LeaveDays
。
NewPeopleObject
是一个包含少量属性和IEnumarable
LeaveDaySummaries
集合的类。
如果不将linq解析为sql错误,我该怎么做才能将Expression传递给Where
子句?
答案 0 :(得分:5)
我无法测试确切的情况(ObjectContext
,ObjectSet
等表示一些较旧的EF版本),但我能够在最新的EF6.1.3中重现上述运行时异常(使用DbContext
和DbSet
)也是如此。
忘记Func
方法 - EF需要将查询转换为SQL,因此Expression
是必须的。这又需要AsQueryable()
。到现在为止还挺好。
问题是EF不喜欢表达式树中的自定义方法 - 它通常没有顶级方法的问题,但是肯定存在嵌套调用的问题,如示例中(有问题的表达式是外部选择表达式的一部分)
我不知道为什么,但在大多数情况下(包括这个以及可能的话)将表达式放在查询之外的局部变量中并在里面使用它解决了这个问题:
var leaveDayPredicate = LeaveDayExpressions.IsInDatesRange(startDate, endDate);
var result = this.ObjectContext.People.Select(p => new NewPeopleObject
{
Guid = p.Guid,
FirstName = p.FirstName,
LastName = p.LastName,
LeaveDays = p.CalendarData.LeaveDays.AsQueryable()
.Where(leaveDayPredicate)
.Select(ld => new LeaveDaySummary
{
StartDate = ld.StartDate,
EndDate = ld.EndDate,
})
});
对于更高级的场景(比如使用外部表达式中的某些内容),您可能需要一些表达式处理库,例如LINQKit Invoke
/ Expand
/ AsExpandable
自定义扩展方法等。