C# 使用Func<;生成LambdaExpression&燃气轮机;其中returnType为IQueryable<;T>;
我正在尝试创建一种基于自己的id获取EntityFramework对象的通用方法,而无需将lambda表达式作为参数传递给方法C# 使用Func<;生成LambdaExpression&燃气轮机;其中returnType为IQueryable<;T>;,c#,generics,C#,Generics,我正在尝试创建一种基于自己的id获取EntityFramework对象的通用方法,而无需将lambda表达式作为参数传递给方法GetById()。对于下面的代码,实体T的类型为Message,是实现GetById()的类所知道的,并且具有一个属性MessageId,以及几个其他属性。在下面的示例中,MessageId名称已经硬编码,因为这仍然是实验性的-从T中提取id属性名称以后很容易修复 我一直在努力寻找一种方法来构造一个简单的LambdaExpression,它将IQueryable作为参数
GetById()
。对于下面的代码,实体T
的类型为Message
,是实现GetById()
的类所知道的,并且具有一个属性MessageId
,以及几个其他属性。在下面的示例中,MessageId
名称已经硬编码,因为这仍然是实验性的-从T
中提取id属性名称以后很容易修复
我一直在努力寻找一种方法来构造一个简单的LambdaExpression
,它将IQueryable
作为参数类型,并希望有人能知道如何实现这一点。我之所以想要IQueryable
,是因为我的底层通道工厂提供程序需要它来进行更复杂的查询
下面代码中带有var exp=Expression.Lambda
的行显示了我希望以其结尾的表达式函数类型定义,但该行给出了异常:
System.Boolean类型的表达式不能用于返回类型IQueryable
这是因为主体具有Boolean
类型,而我的表达式参数queryParamtRet
的类型为IQueryable
。此外,如果我将主体类型更改为IQueryable
,我将无法找到属性MessageId
,因为类型不再是T
类型,而是IQueryable
public T GetById(int-id)
{
var queryParamLeft=表达式
.参数(typeof(System.Data.Entity.DbSet),“o”);
var queryParamRet=表达式
.参数(类型(IQueryable),“o”);
var entityFrameworkType=表达式
.参数(类型为(T),“o”);
var queryProperty=表达式
.PropertyOrField(entityFrameworkType,“MessageId”);
变量体=表达式
.Equal(queryProperty,Expression.Constant(id));
var exp=表达式
兰姆达先生(
身体,
槲皮素;
var returnXml=DoWithChannel(通道
=>channel.Load(serializer.Serialize(exp));
}
TLDR:写出要为其创建表达式的代码,然后故意创建表达式,从任何内部表达式开始,然后再将其组合到外部表达式中
如果您将预期的代码作为函数编写,它将如下所示
public static IQueryable<T> FilterADbSet(DbSet<T> dbSet)
{
return Queryable.Where<T>(dbSet, o => o.MessageId == 34);
}
publicstaticiqueryable过滤器数据库集(DbSet-DbSet)
{
返回Queryable.Where(dbSet,o=>o.MessageId==34);
}
它有一个类型为DbSet
的输入参数,一个类型为IQueryable
的输出,并使用DbSet变量的参数和表达式调用Queryable.Where
从外向内工作,首先需要构建表达式以传递给where子句。您已经在代码中这样做了
接下来,需要为where子句创建lambda表达式
var whereClause = Expression.Equal(queryProperty, Expression.Constant(id));
var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);
var whereClause=Expression.Equal(queryProperty,Expression.Constant(id));
var whereClauseLambda=Expression.Lambda(whereClause,entityFrameworkType);
接下来,如注释所示,您需要使用Expression.Call来创建一个主体
下面是我让代码正常工作的最终结果
static Expression<Func<IQueryable<T>, IQueryable<T>>> WhereMethodExpression = v => v.Where(z => true);
static MethodInfo WhereMethod = ((MethodCallExpression)WhereMethodExpression.Body).Method;
public T GetById(int id)
{
var queryParamLeft = Expression
.Parameter(typeof(System.Data.Entity.DbSet<T>), "dbSet");
var entityFrameworkType = Expression
.Parameter(typeof(T), "entity");
var queryProperty = Expression
.PropertyOrField(entityFrameworkType, "MessageId");
var whereClause = Expression
.Equal(queryProperty, Expression.Constant(id));
var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);
var body = Expression.Call(
WhereMethod,
queryParamLeft,
whereClauseLambda
);
var exp = Expression
.Lambda<Func<System.Data.Entity.DbSet<T>, IQueryable<T>>>(
body,
queryParamLeft);
var returnXml = DoWithChannel(channel
=> channel.Load(serializer.Serialize(exp)));
}
静态表达式WhereMethodExpression=v=>v.Where(z=>true);
静态MethodInfo WhereMethod=((MethodCallExpression)WhereMethodExpression.Body);
公共T GetById(int-id)
{
var queryParamLeft=表达式
.参数(typeof(System.Data.Entity.DbSet),“DbSet”);
var entityFrameworkType=表达式
.参数(类型(T),“实体”);
var queryProperty=表达式
.PropertyOrField(entityFrameworkType,“MessageId”);
var where子句=表达式
.Equal(queryProperty,Expression.Constant(id));
var whereClauseLambda=Expression.Lambda(whereClause,entityFrameworkType);
var body=Expression.Call(
方法,
queryParamLeft,
第14条
);
var exp=表达式
兰姆达先生(
身体,
查询参数(左);
var returnXml=DoWithChannel(通道
=>channel.Load(serializer.Serialize(exp));
}
Queryable.Where
queryParamLeft
传入。不需要queryParamRet看起来您的表达式中缺少了一个步骤——如果它是以c#中的LINQ语句编写的,它会是什么样子
dbSet.Where(o=>o.MessageId==id)
maybe?您缺少Expression.Call(Queryable.Where,Expression.Lambda)
static Expression<Func<IQueryable<T>, IQueryable<T>>> WhereMethodExpression = v => v.Where(z => true);
static MethodInfo WhereMethod = ((MethodCallExpression)WhereMethodExpression.Body).Method;
public T GetById(int id)
{
var queryParamLeft = Expression
.Parameter(typeof(System.Data.Entity.DbSet<T>), "dbSet");
var entityFrameworkType = Expression
.Parameter(typeof(T), "entity");
var queryProperty = Expression
.PropertyOrField(entityFrameworkType, "MessageId");
var whereClause = Expression
.Equal(queryProperty, Expression.Constant(id));
var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);
var body = Expression.Call(
WhereMethod,
queryParamLeft,
whereClauseLambda
);
var exp = Expression
.Lambda<Func<System.Data.Entity.DbSet<T>, IQueryable<T>>>(
body,
queryParamLeft);
var returnXml = DoWithChannel(channel
=> channel.Load(serializer.Serialize(exp)));
}