LINQ to Entities - Addressing class properties with their string names

前端 未结 3 1259
小蘑菇
小蘑菇 2021-01-16 20:12

I have a Kendo grid that has serverside filtering turned on. The field to filter by is passed as a string. For example, I want to filter by \"SampleId\". Now, I need to writ

3条回答
  •  醉话见心
    2021-01-16 21:02

    if you like expressions, you can use them to get the value of a property like so (taken from some helpers i have made in LinqPad so it might not be full code):

    public static class Helper {
    
        public static IEnumerable Select( this IEnumerable enumerable, string memberName ) {
            IQueryable queryable = enumerable.AsQueryable();
            LambdaExpression expression = PredicateFor( queryable.ElementType, memberName );
            return CreateQuery( queryable, "Select", new[] { expression.ReturnType }, expression ).Cast();
        }
    
        public static MemberExpression NestedPropertyOrField(this Expression expression, string nestedPropertyOrFieldName) {
            MemberExpression e;
    
            if (nestedPropertyOrFieldName.IndexOf('.') >= 0) {
                var split = nestedPropertyOrFieldName.Split(new[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);
    
                if (split.Length > 0) {
                    e = Expression.PropertyOrField(expression, split[0]);
    
                    if (split.Length > 1) {
                        e = NestedPropertyOrField(e, split[1]);
                    }
                } else {
                    throw new ArgumentException("'" + nestedPropertyOrFieldName + "' is not a member of type '" + expression.Type.AssemblyQualifiedName + "'");
                }
            } else {
                e = Expression.PropertyOrField(expression, nestedPropertyOrFieldName);
            }
    
            return e;
        }
    
        private static IEnumerable CreateQuery( IEnumerable enumerable, string method, Type[] typeArguments, params Expression[] arguments ) {
            IQueryable queryable = enumerable.AsQueryable();
            Type[] typeArgs = new[] { queryable.ElementType }.Concat( typeArguments ?? new Type[ 0 ] ).ToArray();
            Expression[] args = new[] { queryable.Expression }.Concat( arguments ?? new Expression[ 0 ] ).ToArray();
            MethodCallExpression methodCallExpression = Expression.Call( typeof( Queryable ), method, typeArgs, args );
            return queryable.Provider.CreateQuery( methodCallExpression );
        }
    
        internal static LambdaExpression PredicateFor( Type elementType, string memberName ) {
            var pe = Expression.Parameter( elementType, "@item" );
            Expression expression = pe;
    
            if ( memberName.StartsWith( "@item", StringComparison.OrdinalIgnoreCase ) ) {
                memberName = memberName.Substring( 5 );
            }
    
            if ( memberName.Length > 0 )
                expression = NestedPropertyOrField( expression, memberName );
    
            var delegateType = Expression.GetFuncType( elementType, expression.Type );
            return Expression.Lambda( delegateType, expression, new[] {pe} );
        }
    }
    

    and then do

    string propertyName = // get property name from somewhere, ie: "SomeObject.NestedProperty.ID"
    db.Cases.Select(propertyName).Where(targetlist.Contains);
    

提交回复
热议问题