我正在尝试动态过滤select子句中的字段,类似于帖子dynamically selecting fields in a linq query中描述的用户请求的字段。 (我在下面描述我的问题,所以你不需要去链接)
我想要做的就是定义一个查询,然后在运行时确定哪些字段是select语句的一部分,哪些字段被过滤掉。
QueryFilter filter = new QueryFilter {
ShowClientInfo = false,
ShowPackaging = true,
ShowName = true,
ShowWeight = false
};
//Below is a sample linq query that works without desired filtering.
// Comments are to the right of the fields I want filterd with the object above
var testQuery = db.Client
.Where(c => c.ID == clientId)
.Select(c =>
new
{
ClientInfo = c, // <== Supress this
Packaging = c.ClientPackaging // <== Show this
.Where(cp => !cp.IsDeleted)
.Select(cp =>
new
{
Name = cp.Name, // <== Show this
Weight = cp.Weight // <== Suppress this
}
).ToList()
}
).FirstOrDefault();
相关问题的第一个答案是不够的,所以我不打算进一步讨论。这是不够的,因为linq语句仍然会在数据库中查询特定字段,并且只会在返回时不分配值。
Ivan Stoev的第二个令人敬畏的回答是我想要扩展的内容。此答案可防止字段甚至成为数据库查询的一部分,并且是首选。但这仅适用于linq查询的最外层选择。我遇到问题的部分是创建一个辅助方法,它将在select语句中的子查询上工作。
出现问题的原因是,第一次使用的重载是IQueryable类型,select中的嵌套查询类型为IEnumerable,因此不会映射到答案的当前扩展名。
适用于最外层选择语句的other post mentioned above扩展
public static class MyExtensions
{
public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, object options)
{
var memberInit = (MemberInitExpression)selector.Body;
var bindings = new List<MemberBinding>();
foreach (var binding in memberInit.Bindings)
{
var option = options.GetType().GetProperty("Show" + binding.Member.Name);
if (option == null || (bool)option.GetValue(options)) bindings.Add(binding);
}
var newSelector = Expression.Lambda<Func<TSource, TResult>>(
Expression.MemberInit(memberInit.NewExpression, bindings), selector.Parameters);
return source.Select(newSelector);
}
}
这是我的示例查询,它与第一个Select一起使用,但嵌套的select语句不起作用,因为它们需要是IEnumerable扩展。
public class QueryFilter
{
public bool ShowClientInfo {get;set;}
public bool ShowPackaging {get;set;}
public bool ShowName {get;set;}
public bool ShowWeight {get;set;}
}
QueryFilter filter = new QueryFilter {
ShowClientInfo = false,
ShowPackaging = true,
ShowName = true,
ShowWeight = false
};
var testQuery = db.Client
.Where(c => c.ID == clientId)
.Select(c =>
new
{
ClientInfo = c,
Packaging = c.ClientPackaging
.Where(cp => !cp.IsDeleted)
.Select(cp => // <==== This select does not work
new
{
Name = cp.Name,
Weight = cp.Weight,
packages = cp.ShipmentPackage
.Select(sp => // <==== Neither does this
new
{
Dimension_x = sp.Dimension_x,
Dimension_y = sp.Dimension_y,
Dimension_z = sp.Dimension_z
}, filter //<== additional filter parameter for the select statement
).ToList()
}, filter //<== additional filter parameter for the select statement
).ToList()
}, filter //<== additional filter parameter for the select statement
).FirstOrDefault();
我在.Select中的两个嵌套查询中遇到的错误是:
方法'选择'有1个参数,但是用2个参数调用
我需要创建一个IEnumerable版本的方法,在这种情况下可以使用。
如何将该方法创建为IEnumerable?