[英]How to use a variable when making a lambda expression using Expression.Lambda<Func<>>()
I have a linq query which is as follows:我有一个 linq 查询,如下所示:
var query = _appDbContext.Persons
.Where(p => p.Id == 123)
.Select(lambda)
.ToList();
I use lambda because i have a variable in my select statement.我使用 lambda 因为我的 select 语句中有一个变量。 The lambda: lambda:
var wantedData = "Adress";
var x = Expression.Parameter(typeof(Person), "x");
var body = Expression.PropertyOrField(x, wantedData);
var lambda = Expression.Lambda<Func<Person, Adress>>(body, x);
The query will return the addresses for person with id 123. Let's say instead of the addresses I would like to recieve all subscriptions this person has.该查询将返回 id 为 123 的人的地址。假设我希望接收此人的所有订阅,而不是地址。 Only setting wantedData = "Subscription"
will not work, because of the "Adress" in the lambda statement.由于 lambda 语句中的“地址”,仅设置wantedData = "Subscription"
将不起作用。 So I'm looking for a way to use a variable to change "Adress" in the lambda statement.所以我正在寻找一种方法来使用变量来更改 lambda 语句中的“地址”。
I tried the following, which obviously does not work.我尝试了以下方法,这显然不起作用。
var lambda = Expression.Lambda<Func<Person, wantedData>>(body, x);
Is there a way to do this?有没有办法做到这一点?
Ok, I managed to create a generic query method that takes an Expression as parameter.好的,我设法创建了一个以表达式为参数的通用查询方法。
EDIT: This will receive a string value and will try to match it with an existing property on your Person
class.编辑:这将收到一个字符串值,并将尝试将其与您的Person
class 上的现有属性匹配。
private IEnumerable<TResult> GetPersonData<TResult>(Expression<Func<Person, TResult>> selectExpression)
{
return _dbContext.Persons
// .Where(filter)
.Select(selectExpression)
.ToList();
}
public IEnumerable<object> GetData(string dataPropertyName)
{
switch(dataPropertyName) {
case nameof(Person.Address): return GetPersonData(p => p.Address);
case nameof(Person.Subscription): return GetPersonData(p => p.Subscription);
// other cases
default: throw new InvalidArgumentException("Invalid property name");
}
}
note that this code is just an example written on the spot and it might not work directly with copy-paste请注意,此代码只是当场编写的示例,它可能无法直接用于复制粘贴
I've made something similar to an OrderBy
and tweak it a little for your select.我做了一些类似于OrderBy
的东西,并为你的 select 稍微调整了一下。 This only works if you know the return type.这仅在您知道返回类型时才有效。 You can create an extension method with the following code:您可以使用以下代码创建扩展方法:
public static IQueryable<TResult> Select<T,TResult>(this IQueryable<T> source, string propertyName)
{
var prop = typeof(T).GetProperties()
.FirstOrDefault(x => x.Name.ToUpper() == propertyName.ToUpper());
ParameterExpression pe = Expression.Parameter(typeof(T), "x");
MemberExpression body = Expression.Property(pe, prop.Name);
LambdaExpression lambda = Expression.Lambda(body, new ParameterExpression[] { pe });
MethodCallExpression selectCallExpression = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { source.ElementType, prop.PropertyType },
source.Expression,
lambda);
return source.Provider.CreateQuery<TResult>(selectCallExpression);
}
That way, you can use it like:这样,您可以像这样使用它:
var query = _appDbContext.Persons
.Where(p => p.Id == 123)
.Select<Person,string>(wantedData)
.ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.