使用 Func 作为 LinqToEntities 的参数
Using Func as parameter for LinqToEntities
我有一个 Linq 查询来获取我的 EF 数据。我的查询连接了 4 个表并将结果选择为非规范化类型。我将经常需要此查询,但使用不同的谓词。 List-ExtensionMethods(例如 .Where()
正在使用 Func<T,bool>
作为参数,我想做同样的事情 - 但我找不到在我的方法中访问我的谓词的方法。
public DenormalizedType GetData(Func<Thing, bool> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
// => HowToWhere ???
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}
关于这个问题我有 3 个问题。
首先(显然):如何调用我的谓词以使用动态 where-clause?
其次:如果我最初的想法不起作用(因为 teovankots 的回答表明,我的方法对 LinqToEntities 无效)是否有可能仅创建一个连接方法?
第三:什么是 return 我的结果到另一个软件组件的最佳性能方法?
您可以轻松调用它。安装 this package,添加:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
where predicate.Invoke(some) //check this
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}
你应该知道 Func<T1,T2>
是一种方法。使用此签名:
T2 predicate(T1 parameter) { /*...*/ }
你的第二个问题取决于你如何连接你的组件。但是只要你得到 DenormalizedType
而不是 DbEntity 你的例子看起来就没问题。
至少我找到了解决问题的方法 - 但我非常感谢提示和/或让它变得更好的方法,因为我无法想象这是圣杯甚至接近圣杯...
然而,第一步是我的加入,我return作为IQueryable。重要提示:这里不要使用,因为否则 dbContext 将被释放,这在使用 IQueryable 时不是很好:
private static MyDbContext _dbContext;
private static IQueryable<DenormalizedType> SelectType()
{
_dbContext = new MyDbContext();
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
};
return myData;
}
我今天学到了很多东西。例如:IEnumerable 和 IQueryable 都有一个扩展方法 .Where()
。但是只有 IEnumerable.Where()
有一个 Func<T,bool>
作为参数。 IQueryable 为其 Where()
采用 Expression<Func<T,bool>>
。如果我想要执行我的查询,在我所有的条件下,我需要使用 IQueryable 类型,只要我的所有位置都没有被执行。所以我需要仔细看看 Expression-Type。我不明白这一切到底是做什么的,但它确实有效 ;)
我必须做的第一件事是编写我的 Where-Methods.. 在我读完这篇文章后,这很容易:Entity Framework Filter "Expression<Func<T, bool>>"。该方法如下所示:
public static IQueryable<DenormalizedType> SelectWhereCriteria(IQueryable<DenormalizedType> data, Expression<Func<DenormalizedType, bool>> predicate)
{
return data.Where(predicate);
}
表达式本身有点复杂,因为我有一个应该 select 指定过滤器的选择枚举。表达式看起来像:
Expression<Func<DenormalizedType, bool>> FilterBySelection(Selection selection)
{
switch(selection)
{
case Selection.Active:
return x => x.IsActive == true;
case Selection.InActive:
return x => x.IsActive == false;
case Selection.SomeOtherSelection:
return x => x.SomeOther == "Criteria"
default:
return x => true;
}
}
这个表达式在我的 IQueryable 上运行良好:
var selectedQuery = DataHandler.SelectWhereCriteria(query, FilterBySelection(selection));
我现在唯一需要的就是订购。我从 MarcGravell(顺便说一句,多么天才)Dynamic LINQ OrderBy on IEnumerable<T> 那里找到了一些非常酷的东西,他在其中发布了一些代码作为对 OrderBy PropertyName 的答案,您可以使用这些代码。他的第一段代码采用一个 IQueryable,按 PropertyName 对其进行排序(他还为 Descending OrderyBy 提供扩展)和 returns 一个 IOrderedQueryable。 ToList()-Operation 是我执行的最后一个操作。
还有一件事:不要忘记处理 DbContext:
public static void Dispose()
{
_dbContext.Dispose();
}
EF 查询提供程序需要将 LINQ 查询表达式树转换为 SQL,这在您传递 Func<...>
时是不可能的(更一般地说,调用表达式 如委托、未知方法等)。
很快,Func<...>
类型参数无法满足您的要求。
使用 Queryable
方法时,首先要考虑的是在 Enumerable
方法中使用 Func<..>
时使用 Expression<Func<...>>
。所以像这样改变你的方法参数:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
不幸的是,开箱即用不支持在 LINQ 查询语法中使用提供的表达式。为此,您需要一些表达式树处理库。
问题和可能的解决方案在 LINQKit 包页面中进行了说明。包提供的解决方案是通过AsExpandable
和Invoke
自定义扩展方法。
安装nuget package,添加
using LinqKit;
到源代码文件,现在你可以使用类似这样的东西来实现目标:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing.AsExpandable() // <=
join other in dbContext.OtherThing
on some.OtherId equals other.Id
where predicate.Invoke(some) // <=
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}
我有一个 Linq 查询来获取我的 EF 数据。我的查询连接了 4 个表并将结果选择为非规范化类型。我将经常需要此查询,但使用不同的谓词。 List-ExtensionMethods(例如 .Where()
正在使用 Func<T,bool>
作为参数,我想做同样的事情 - 但我找不到在我的方法中访问我的谓词的方法。
public DenormalizedType GetData(Func<Thing, bool> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
// => HowToWhere ???
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}
关于这个问题我有 3 个问题。
首先(显然):如何调用我的谓词以使用动态 where-clause?
其次:如果我最初的想法不起作用(因为 teovankots 的回答表明,我的方法对 LinqToEntities 无效)是否有可能仅创建一个连接方法?
第三:什么是 return 我的结果到另一个软件组件的最佳性能方法?
您可以轻松调用它。安装 this package,添加:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
where predicate.Invoke(some) //check this
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}
你应该知道 Func<T1,T2>
是一种方法。使用此签名:
T2 predicate(T1 parameter) { /*...*/ }
你的第二个问题取决于你如何连接你的组件。但是只要你得到 DenormalizedType
而不是 DbEntity 你的例子看起来就没问题。
至少我找到了解决问题的方法 - 但我非常感谢提示和/或让它变得更好的方法,因为我无法想象这是圣杯甚至接近圣杯...
然而,第一步是我的加入,我return作为IQueryable。重要提示:这里不要使用,因为否则 dbContext 将被释放,这在使用 IQueryable 时不是很好:
private static MyDbContext _dbContext;
private static IQueryable<DenormalizedType> SelectType()
{
_dbContext = new MyDbContext();
var myData = (from some in dbContext.Thing
join other in dbContext.OtherThing
on some.OtherId equals other.Id
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
};
return myData;
}
我今天学到了很多东西。例如:IEnumerable 和 IQueryable 都有一个扩展方法 .Where()
。但是只有 IEnumerable.Where()
有一个 Func<T,bool>
作为参数。 IQueryable 为其 Where()
采用 Expression<Func<T,bool>>
。如果我想要执行我的查询,在我所有的条件下,我需要使用 IQueryable 类型,只要我的所有位置都没有被执行。所以我需要仔细看看 Expression-Type。我不明白这一切到底是做什么的,但它确实有效 ;)
我必须做的第一件事是编写我的 Where-Methods.. 在我读完这篇文章后,这很容易:Entity Framework Filter "Expression<Func<T, bool>>"。该方法如下所示:
public static IQueryable<DenormalizedType> SelectWhereCriteria(IQueryable<DenormalizedType> data, Expression<Func<DenormalizedType, bool>> predicate)
{
return data.Where(predicate);
}
表达式本身有点复杂,因为我有一个应该 select 指定过滤器的选择枚举。表达式看起来像:
Expression<Func<DenormalizedType, bool>> FilterBySelection(Selection selection)
{
switch(selection)
{
case Selection.Active:
return x => x.IsActive == true;
case Selection.InActive:
return x => x.IsActive == false;
case Selection.SomeOtherSelection:
return x => x.SomeOther == "Criteria"
default:
return x => true;
}
}
这个表达式在我的 IQueryable 上运行良好:
var selectedQuery = DataHandler.SelectWhereCriteria(query, FilterBySelection(selection));
我现在唯一需要的就是订购。我从 MarcGravell(顺便说一句,多么天才)Dynamic LINQ OrderBy on IEnumerable<T> 那里找到了一些非常酷的东西,他在其中发布了一些代码作为对 OrderBy PropertyName 的答案,您可以使用这些代码。他的第一段代码采用一个 IQueryable,按 PropertyName 对其进行排序(他还为 Descending OrderyBy 提供扩展)和 returns 一个 IOrderedQueryable。 ToList()-Operation 是我执行的最后一个操作。
还有一件事:不要忘记处理 DbContext:
public static void Dispose()
{
_dbContext.Dispose();
}
EF 查询提供程序需要将 LINQ 查询表达式树转换为 SQL,这在您传递 Func<...>
时是不可能的(更一般地说,调用表达式 如委托、未知方法等)。
很快,Func<...>
类型参数无法满足您的要求。
使用 Queryable
方法时,首先要考虑的是在 Enumerable
方法中使用 Func<..>
时使用 Expression<Func<...>>
。所以像这样改变你的方法参数:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
不幸的是,开箱即用不支持在 LINQ 查询语法中使用提供的表达式。为此,您需要一些表达式树处理库。
问题和可能的解决方案在 LINQKit 包页面中进行了说明。包提供的解决方案是通过AsExpandable
和Invoke
自定义扩展方法。
安装nuget package,添加
using LinqKit;
到源代码文件,现在你可以使用类似这样的东西来实现目标:
public DenormalizedType GetData(Expression<Func<Thing, bool>> predicate)
{
using (var dbContext = new MyDbContext())
{
var myData = (from some in dbContext.Thing.AsExpandable() // <=
join other in dbContext.OtherThing
on some.OtherId equals other.Id
where predicate.Invoke(some) // <=
select new DenormalizedType()
{
SomeEntry = some.Entry
SomeOtherId = some.OtherId
OtherValue = other.Value
}).ToList();
}
}