【问题标题】:LINQ Select columns base on array of string[]LINQ 根据字符串数组选择列 []
【发布时间】:2020-02-04 04:53:56
【问题描述】:

我有一个可以生成查询并将其导出到 excel 的方法。 我希望用户选择他们希望在哪些列上导出。

我的问题有点类似于这个 OP LINQ select property by name

我们可以在string[] columns 列表的基础上创建 LINQ 选择查询,它应该有点类似于 _dbcontext.Person.Select( SelectorFunc(columns) ).SomeOtherQuery().ToList(); 查询和函数SelectorFunc(columns)下面

public Func<Person, string[]> SelectorFunc(string[] columns) {
    //  ninja code!! 
   return " not sure here";
}

如果我不得不像手动操作一样,它有点乱。

var query = _dbcontext.Person.AsQueryable();

if(column == "ID") 
  query = query.Select( x=x.ID);
if(column == "Name") 
  query = query.Select( x=x.Name);

//and the list goes on...

PS: 我非常感谢您的启发,并感谢您的宝贵时间。

【问题讨论】:

  • 您的案例是动态选择,stackoverflow.com/a/45205267/3789481 这个答案是用“,”分隔列字段。所以你的 string[] 列将是 string.Join(",", colums ) 以逗号加入它
  • @TấnNguyên 这正是我想要的!谢谢
  • 我建议,在Selected Columns to Export的基础上生成动态SQL查询[Select statements or Database Views],然后通过EF / ADO.NET使用sql查询,这将非常容易处理并且可维护。

标签: c# linq


【解决方案1】:

这是来自此 OP LINQ : Dynamic select 的重复问题

基于这些答案。

public static Func<T, T> SelectorFunc<T>(string[] columns)
{

        // input parameter "o"
        var xParameter = Expression.Parameter(typeof(T), "o");

        // new statement "new Data()"
        var xNew = Expression.New(typeof(T));

        // create initializers
        var bindings = columns.Select(o => o.Trim())
            .Select(o =>
            {

                // property "Field1"
                var mi = typeof(T).GetProperty(o);

                // original value "o.Field1"
                var xOriginal = Expression.Property(xParameter, mi);

                // set value "Field1 = o.Field1"
                return Expression.Bind(mi, xOriginal);
            }
        );

        // initialization "new Data { Field1 = o.Field1, Field2 = o.Field2 }"
        var xInit = Expression.MemberInit(xNew, bindings);

        // expression "o => new Data { Field1 = o.Field1, Field2 = o.Field2 }"
        var lambda = Expression.Lambda<Func<T, T>>(xInit, xParameter);

        // compile to Func<Data, Data>
        return lambda.Compile();
}

并且使用该函数将是_dbcontext.Person.SomeOtherQuery().Select( SelectorFunc&lt;Person&gt;(columns) ).ToList()

感谢@Tấn Nguyên 的回答。

【讨论】:

    【解决方案2】:

    我认为这应该会有所帮助: 我从这里找到它 Dynamically select properties by string names

    这是你的对象:

        public class Foo
    {
        public string Property1 {get;set;}
        public string Property2 {get;set;}  
    }
    

    这是你的助手类:

      public static class ExpressionTreeHelper
    {
        /// <summary> Returns an IEnumerable of anonymous type defined by <paramref name="properties"/>. </summary>
        public static IEnumerable<dynamic> SelectDynamic<T>(this IEnumerable<T> source, params string[] properties)
        {
            return SelectProperties<T>(source.AsQueryable(), properties).Cast<dynamic>();
        }
    
        private static IQueryable SelectProperties<T>(this IQueryable<T> queryable, IEnumerable<string> propertyNames)
        {
            // get propertyinfo's from original type
            var properties = typeof(T).GetProperties().Where(p => propertyNames.Contains(p.Name));
    
            // Create the x => expression
            var lambdaParameterExpression = Expression.Parameter(typeof(T));
            // Create the x.<propertyName>'s
            var propertyExpressions = properties.Select(p => Expression.Property(lambdaParameterExpression, p));
    
            // Creating anonymous type using dictionary of property name and property type
            var anonymousType = AnonymousTypeUtils.CreateType(properties.ToDictionary(p => p.Name, p => p.PropertyType));
            var anonymousTypeConstructor = anonymousType.GetConstructors().Single();
            var anonymousTypeMembers = anonymousType.GetProperties().Cast<MemberInfo>().ToArray();
    
            // Create the new {} expression using 
            var anonymousTypeNewExpression = Expression.New(anonymousTypeConstructor, propertyExpressions, anonymousTypeMembers);
    
            var selectLambdaMethod = GetExpressionLambdaMethod(lambdaParameterExpression.Type, anonymousType);
            var selectBodyLambdaParameters = new object[] { anonymousTypeNewExpression, new[] { lambdaParameterExpression } };
            var selectBodyLambdaExpression = (LambdaExpression)selectLambdaMethod.Invoke(null, selectBodyLambdaParameters);
    
            var selectMethod = GetQueryableSelectMethod(typeof(T), anonymousType);
            var selectedQueryable = selectMethod.Invoke(null, new object[] { queryable, selectBodyLambdaExpression }) as IQueryable;
            return selectedQueryable;
        }
    
        private static MethodInfo GetExpressionLambdaMethod(Type entityType, Type funcReturnType)
        { 
            var prototypeLambdaMethod = GetStaticMethod(() => Expression.Lambda<Func<object, object>>(default(Expression), default(IEnumerable<ParameterExpression>))); 
            var lambdaGenericMethodDefinition = prototypeLambdaMethod.GetGenericMethodDefinition(); 
            var funcType = typeof(Func<,>).MakeGenericType(entityType, funcReturnType); 
            var lambdaMethod = lambdaGenericMethodDefinition.MakeGenericMethod(funcType); 
            return lambdaMethod; 
        } 
    
        private static MethodInfo GetQueryableSelectMethod(Type entityType, Type returnType)
        { 
            var prototypeSelectMethod = GetStaticMethod(() => Queryable.Select(default(IQueryable<object>), default(Expression<Func<object, object>>))); 
            var selectGenericMethodDefinition = prototypeSelectMethod.GetGenericMethodDefinition();
            return selectGenericMethodDefinition.MakeGenericMethod(entityType, returnType);
        } 
    
        private static MethodInfo GetStaticMethod(Expression<Action> expression)
        { 
            var lambda = expression as LambdaExpression; 
            var methodCallExpression = lambda.Body as MethodCallExpression; 
            return methodCallExpression.Method; 
        } 
    }
    

    并以这种方式调用:

    public static void Main()
    {
        var list = new[] {new Foo { Property1 = "foo1" }, new Foo { Property1 = "foo2" }};
    
        var result = list.SelectDynamic(nameof(property).toString());
    
        result.Dump();
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-04
      • 2011-04-25
      • 1970-01-01
      • 2021-10-23
      • 1970-01-01
      • 2021-11-24
      • 2020-05-22
      • 2022-01-01
      相关资源
      最近更新 更多