以下实体框架查询运行时没有错误。
Predicate<Program> filterProgram;
if (programId.HasValue)
filterProgram = (p => p.Id == programId && !p.IsDeleted);
else
filterProgram = (p => !p.IsDeleted);
var analytics = (from a in repository.Query<Analytic>()
where (a.Marker == "Open" || a.Marker == "LastTouch") &&
a.EntityType == "Proposal" &&
a.Site == "C"
join p in repository.Query<Program>()
on a.EntityId equals p.Id
//where filterProgram(p)
group a
by new { a.LoginSessionId, a.EntityId, p.Id, p.Name } into g
let f = g.OrderBy(x => x.TimestampUtc).FirstOrDefault(x => x.Marker == "Open")
where f != null
let t = g.FirstOrDefault(x => x.Marker == "LastTouch" && x.TimestampUtc > f.TimestampUtc)
select new
{
ProgramId = g.Key.Id,
Program = g.Key.Name,
ProposalId = g.Key.EntityId,
FirstOpen = f,
LastTouch = (t ?? f).TimestampUtc
}).ToList();
但是,如果我取消注释行where filterProgram(p)
,我会收到运行时错误:
LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。
我期待LINQ能够将我的谓词合并到查询中并将其转换为SQL。为什么我会收到此错误,是否有办法以这种方式动态修改where谓词?
答案 0 :(得分:3)
问题是由于Entity Framework需要能够将LINQ查询转换为SQL而引起的。您的LINQ查询被编译为称为表达式树的数据结构,然后将其传递给Entity Framework以转换为SQL。
您有两种选择:
filterProgram
。根据{{1}}的复杂程度,这可能是不可能的。filterProgram
的来电,并将此查询转换为filterProgram
,也许可以致电IEnumerable<T>
。然后,您可以使用.ToList()
2
的例子filterProgram
答案 1 :(得分:2)
将filterProgram
的类型更改为Expression<Func<Program, bool>>
,然后它应该可以在LINQ Where子句中使用。
但有一点需要注意:我设法让它在方法链语法中工作,但在查询语法中没有。
例如,这有效:
dataContext.Programs.Where (filterProgram)
但这不是:
from p in dataContext.Programs
where filterprogram
(编译器抱怨它无法解析Where
和IEnumerable
上提供的方法IQueryable
。)
在您的情况下,替换行
可能是可以接受的join p in repository.Query<Program>()
与
join p in repository.Query<Program>().Where(filterProgram)
答案 2 :(得分:1)
在Linq to Entities中,如果不将查询转换为IEnumerable
,则无法调用外部方法。因此,由于filterProgram
是一种方法,因此您不能在查询中调用。
如果可能,您可以在致电ToList
之前致电FilterProgram
,这样就可以了。
另一种选择可能是将filterProgram
的逻辑插入到查询中。
答案 3 :(得分:1)
问题是linq2entities尝试将表达式树转换为SQL,表达式树在委托类型(filterProgram)上调用方法Invoke
但是没有什么可以阻止你内联谓词
var id= programId.HasValue ? programId.GetValueOrDefault() : -1;
var analytics = (from a in repository.Query<Analytic>()
where (a.Marker == "Open" || a.Marker == "LastTouch") &&
a.EntityType == "Proposal" &&
a.Site == "C"
join p in repository.Query<Program>()
on a.EntityId equals p.Id
where !p.IsDeleted && (!hasValue || p.Id == id)
....
这假设-1是无效的programId