我的模型类与上下文实例严格分开,并且不了解上下文实例。
每个查询都由Expression<Func<Entity, bool>>
这样的表达式驱动,OR
和AND
使用PredicateBuilder
(LinqKit)组合在一起。表达式创建一次(上下文不可知),稍后在不同的线程上针对新创建的上下文(DbContext
派生类)执行。
这适用于许多表达式。但我不知道我将如何引用导航属性无法访问的其他表格:
工作样本(如果我有上下文变量):
using(var context = new MyEntities())
{
Expression<Func<Entity1, bool>> filter = e1 =>
context.Set2.Any(e2 => e2.Data.StartsWith(e1.Prefix));
var result = context.Set1.Where(filter).ToList();
}
但我必须在之前创建表达式,因此无法访问context.Set2
。
是否存在替换context.Set2
的其他语法,可能像DbSet<Entity2>.All
或Queryable<Entity2>.All
或类似的东西,不需要上下文实例?
使用导航属性我已经可以创建带有连接到其他表的表达式,这些表可以生成SQL代码的KB,而不需要引用上下文实例 - 所以我完全不清楚为什么需要一个上下文实例现在
我已经尝试过使用&#34;假的&#34; null实例,但这会抛出NullException:
protected override Expression<Func<Entity1, bool>> BuildFilter()
{
MyEntities fake = null;
return e1 => fake.Set2.Any(e2 => e2.Data.StartsWith(e1.Prefix));
}
答案 0 :(得分:0)
回答自己/我将尝试去的方式
由于我已经在使用PredicateBuilder / LinqKit,我将通过参数将上下文传递给表达式本身并在我真正拥有上下文实例时展开它 - 到目前为止,LinqPad中的预测试表现不错:
Expression<Func<MyEntities, Entity1, bool>> filterTemplate = (ctx, e1) =>
ctx.Set2.Any(e2 => e2.Data.StartsWith(e1.Prefix));
using(var context = new MyEntities())
{
Expression<Func<Entity1, bool>> filter = e1 =>
filterTemplate.Invoke(context, e1); // .Invoke() -> LinqKit
var result = context.Set1.Where(filter.Expand()).ToList(); // .Expand() -> LinqKit
// or
var result = context.Set1.AsExpandable().Where(filter).ToList(); // .AsExpandable() -> LinqKit
}
至少在生产者端类层次结构中,我可以以非破解的方式引入它,因此不必更改现有的1000个表达式,并且只有新方法创建第1001个表达式:
<强>前强>
protected abstract Expression<Func<Entity1, bool>> BuildFilter();
<强>后强>
protected virtual Expression<Func<Entity1, bool>> BuildFilter()
{
throw new NotImplementedException($"Either {nameof(this.BuildFilter)} or {nameof(this.BuildFilter2)} has to be overridden!");
}
protected virtual Expression<Func<MyEntities, Entity1, bool>> BuildFilter2()
{
var legacyFilter = this.BuildFilter();
Expression<Func<MyEntities, Entity1, bool>> result = (context, e1) => legacyFilter.Invoke(e1);
return result.Expand();
}