我有一个简单的自定义QueryProvider,它接受一个表达式,将其转换为SQL并查询sql数据库.
我想在QueryProvider中创建一个小缓存来存储常用对象,这样就可以在没有数据库命中的情况下进行检索.
QueryProvider具有该方法
public object Execute(System.Linq.Expressions.Expression expression)
{
/// Builds an SQL statement from the expression,
/// executes it and returns matching objects
}
Run Code Online (Sandbox Code Playgroud)
缓存作为此QueryProvider类中的字段而存在,并且是一个简单的通用List.
如果我使用List.AsQueryable方法并将上面的表达式传递给List.AsQueryable的Provider的Execute方法,它就不能按预期工作.看起来当表达式被编译时,初始QueryProvider成为一个不可或缺的部分.
是否可以将表达式传递给后续的QueryProvider并根据需要执行表达式?
调用代码看起来模糊如下:
public class QueryProvider<Entity>()
{
private List<TEntity> cache = new List<Entity>();
public object Execute(System.Linq.Expressions.Expression expression)
{
/// check whether expression expects single or multiple result
bool isSingle = true;
if (isSingle)
{
var result = this.cache.AsQueryable<Entity>().Provider.Execute(expression);
if (result != null)
return result;
}
/// cache failed, hit database
var qt = new QueryTranslator(); …Run Code Online (Sandbox Code Playgroud) 我正在尝试在我的EF过滤代码中使用谓词.
这有效:
IQueryable<Customer> filtered = customers.Where(x => x.HasMoney && x.WantsProduct);
Run Code Online (Sandbox Code Playgroud)
但是这个:
Predicate<T> hasMoney = x => x.HasMoney;
Predicate<T> wantsProduct = x => x.WantsProduct;
IQueryable<Customer> filtered = customers.Where(x => hasMoney(x) && wantsProduct(x));
Run Code Online (Sandbox Code Playgroud)
在运行时失败:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
Run Code Online (Sandbox Code Playgroud)
我不能使用第一个选项,因为这是一个简单的例子,实际上,我正在尝试将一堆谓词组合在一起(使用和不使用等)以实现我想要的功能.
如何让EF Linq提供程序"理解"我的谓词?
如果我使用a,我会得到相同的结果Func<T, bool>.它适用于Expression<Func<T>>,但我不能将表达式组合在一起进行复杂的过滤.如果可能的话,我宁愿避免使用外部库.
更新:
如果无法做到这一点,我有什么选择?也许以某种方式组合/或/和表达表达式以达到同样的效果?
我需要对ObjectSet进行一些过滤,以通过这样做获取我需要的实体:
query = this.ObjectSet.Where(x => x.TypeId == 3); // this is just an example;
Run Code Online (Sandbox Code Playgroud)
稍后在代码中(以及在启动延迟执行之前)我再次过滤查询,如下所示:
query = query.Where(<another lambda here ...>);
Run Code Online (Sandbox Code Playgroud)
到目前为止,这很有效.
这是我的问题:
实体包含DateFrom属性和DateTo属性,它们都是DataTime类型.它们代表了一段时间.
我需要过滤的实体只拿到那些一个部分集合的时间段.集合中的句点不一定是连续的,因此,检索实体的逻辑看起来像这样:
entities.Where(x => x.DateFrom >= Period1.DateFrom and x.DateTo <= Period1.DateTo)
||
entities.Where(x => x.DateFrom >= Period2.DateFrom and x.DateTo <= Period2.DateTo)
||
Run Code Online (Sandbox Code Playgroud)
......以及集合中所有时期的不断变化.
我试过这样做:
foreach (var ratePeriod in ratePeriods)
{
var period = ratePeriod;
query = query.Where(de =>
de.Date >= period.DateFrom …Run Code Online (Sandbox Code Playgroud) 我有一个Product在类库项目中命名的类.我SubSonic SimpleRepository用来坚持对象.我在Product课堂上有如下方法:
public static IList<Product> Load(Expression<Func<Product, bool>> expression)
{
var rep=RepoHelper.GetRepo("ConStr");
var products = rep.Find(expression);
return products.ToList();
}
Run Code Online (Sandbox Code Playgroud)
我正在调用这个函数:
private void BindData()
{
var list = Product.Load(x => x.Active);//Active is of type bool
rptrItems.DataSource = list;
rptrItems.DataBind();
}
Run Code Online (Sandbox Code Playgroud)
调用Load从BindData引发异常:
variable 'x' of type 'Product' referenced from scope '', but it is not defined
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题.
编辑: - 通过单步执行SubSonic代码,我发现该函数抛出了错误
private static Expression Evaluate(Expression e)
{
if(e.NodeType == ExpressionType.Constant)
return e; …Run Code Online (Sandbox Code Playgroud) 我正在考虑使用Linq Expression作为字典中的键.但是,我担心我会得到奇怪的结果,因为我不知道Linq表达式如何确定Equality.
派生自Expression的类是否比较值相等或引用相等?或者换句话说,
Expression<Func<object>> first = () => new object();
Expression<Func<object>> second = ()=>new object();
bool AreTheyEqual = first == second;
Run Code Online (Sandbox Code Playgroud) 我正在构建一个C#表达式到Javascript的转换器,沿着Linq-to-SQL的路线,但我遇到了编译器生成的表达式树的问题.
我遇到的特殊问题是处理MemberExpression编译器生成的值,但是没有CompilerGeneratedAttribute在其类型上指定的值.
这是我一直在尝试的简化版本:
void ProcessMemberExpression(MemberExpression memberX) {
var expression = memberX.Expression;
var expressionType = expression.Type;
var customAttributes = expressionType.GetCustomAttributes(true);
var expressionTypeIsCompilerGenerated = customAttributes.Any(x => x is CompilerGeneratedAttribute);
if (expressionTypeIsCompilerGenerated) {
var memberExpressionValue = Expression.Lambda(memberX).Compile().DynamicInvoke();
... do stuff ...
}
else {
... do other stuff ...
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我打开了一个Visual Studio调试会话,我发现它(在立即窗口中运行):
expressionType.Name
"<>c__DisplayClass64"
expressionType.GetCustomAttributes(true)
{object[0]}
expressionType.GetCustomAttributes(true).Length
0
Run Code Online (Sandbox Code Playgroud)
所以我在这里有一个显然是编译器生成的类,没有自定义属性,因此没有CompilerGeneratedAttribute!因此,do other stuff当我打算公正时,我的代码将会do stuff.
如果有人能帮助我,我会非常感激.如果可能的话,我真的宁愿做任何肮脏的事情就像匹配类似的expressionType.Name东西<>.*__DisplayClass.
我正在使用这个动态的linq orderby函数,我从这里得到了.
这适用于嵌套属性,所以我可以这样做:
var result = data.OrderBy("SomeProperty.NestedProperty");
Run Code Online (Sandbox Code Playgroud)
问题是,如果SomeProperty为null,那么在NestedProperty上执行OrderBy会抛出臭名昭着的"对象引用未设置为对象的实例".
我的猜测是我需要自定义以下行来处理异常:
expr = Expression.Property(expr, pi);
// Or
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
Run Code Online (Sandbox Code Playgroud)
我考虑创建一个语句体,在最坏的情况下我可以使用try catch,但这不起作用,因为你不能在orderby linq语句中使用语句体:"带有语句体的lambda表达式无法转换为表达树"
我迷失在这里,有关如何实现这一目标的任何建议?
顺便说一句,这是针对Linq to Objects,而不是数据库相关的.
我试图用System.Linq.Expressions创建一个switch表达式:
var value = Expression.Parameter(typeof(int));
var defaultBody = Expression.Constant(0);
var cases1 = new[] { Expression.SwitchCase(Expression.Constant(1), Expression.Constant(1)), };
var cases2 = new SwitchCase[0];
var switch1 = Expression.Switch(value, defaultBody, cases1);
var switch2 = Expression.Switch(value, defaultBody, cases2);
Run Code Online (Sandbox Code Playgroud)
但在最后一行我得到一个ArgumentException:
需要非空收集.参数名称:案例
这个例外的原因是什么?这可能是Expression.Switch(...)中的一个错误?
在C#中,只有"默认"部分的开关是正确的:
switch(expr) {
default:
return 0;
}//switch
Run Code Online (Sandbox Code Playgroud)
UPD:我已经向GitHub上的CoreFX回购提交了一个问题
我已经看过类似这个问题的其他问题,但我找不到任何可行的答案.
我一直在使用以下代码生成唯一键,用于将我的linq查询的结果存储到缓存中.
string key = ((LambdaExpression)expression).Body.ToString();
foreach (ParameterExpression param in expression.Parameters)
{
string name = param.Name;
string typeName = param.Type.Name;
key = key.Replace(name + ".", typeName + ".");
}
return key;
Run Code Online (Sandbox Code Playgroud)
它似乎适用于包含整数或布尔值的简单查询,但是当我的查询包含嵌套的常量表达式时,例如
// Get all the crops on a farm where the slug matches the given slug.
(x => x.Crops.Any(y => slug == y.Slug) && x.Deleted == false)
Run Code Online (Sandbox Code Playgroud)
返回的密钥是:
(True AndAlso(Farm.Crops.Any(y =>(value(OzFarmGuide.Controllers.FarmController + <> c__DisplayClassd).slug == y.Slug))AndAlso(Farm.Deleted == False)))
正如您所看到的,我传递的任何裁剪名称都会给出相同的关键结果.有没有办法可以提取给定参数的值,以便我可以区分我的查询?
还转换y为说出正确的类型名称会很好.....
我正在尝试编写一个方法,在具有特定自定义属性的程序集中查找所有类型.我还需要能够提供匹配的字符串值.需要注意的是,我希望能够在任何类上运行它并返回任何值.
例如:我想执行这样的调用
Type tTest = TypeFinder.GetTypesWithAttributeValue(Assembly.Load("MyAssembly"), typeof(DiagnosticTestAttribute), "TestName", "EmailTest");
Run Code Online (Sandbox Code Playgroud)
到目前为止我的方法看起来像这样:
public static Type GetTypesWithAttributeValue(Assembly aAssembly, Type tAttribute, string sPropertyName, object oValue)
{
object oReturn = null;
foreach (Type type in aAssembly.GetTypes())
{
foreach (object oTemp in type.GetCustomAttributes(tAttribute, true))
{
//if the attribute we are looking for matches
//the value we are looking for, return the current type.
}
}
return typeof(string); //otherwise return a string type
}
Run Code Online (Sandbox Code Playgroud)
我的属性看起来像这样:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class DiagnosticTestAttribute : Attribute
{
private string _sTestName …Run Code Online (Sandbox Code Playgroud) c# ×10
linq-expressions ×10
linq ×7
.net ×2
lambda ×2
caching ×1
expression ×1
reflection ×1
subsonic3 ×1