动态选择linq子查询

时间:2016-10-28 02:02:36

标签: c# linq

我正在尝试动态过滤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?

0 个答案:

没有答案