LINQ to Entities - Addressing class properties with their string names

前端 未结 3 1215
小蘑菇
小蘑菇 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 20:56

    I didn't think any of these answered actually how to do the getproperty so included my working code after further research. mymodelclass is the class of the entity/model used to MyFilteredData.

            var srchItem1 = typeof(mymodelclass).GetProperty("Name");
            var srchItem2 = typeof(mymodelclass).GetProperty("Description");
            var srchItem3 = typeof(mymodelclass).GetProperty("LongDescription");
            if (MySearchText != null && srchItem1 != null)
                {
                    if (srchItem2 == null) { srchItem2 = srchItem1; }
                    if (srchItem3 == null) { srchItem3 = srchItem1; }
                    MyFilteredData = MyFilteredData.
                            Where(c => srchItem1.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower()) ||
                            srchItem2.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower()) ||
                            srchItem3.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower())
                    );
                }
    
    0 讨论(0)
  • 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<T> Select<T>( this IEnumerable enumerable, string memberName ) {
            IQueryable queryable = enumerable.AsQueryable();
            LambdaExpression expression = PredicateFor( queryable.ElementType, memberName );
            return CreateQuery( queryable, "Select", new[] { expression.ReturnType }, expression ).Cast<T>();
        }
    
        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<string>(propertyName).Where(targetlist.Contains);
    
    0 讨论(0)
  • 2021-01-16 21:05

    You can use an extension method and attach it to the class.

    That method should use reflection to retrieve the property from the object.

    Here are the pointers:

    • Extension methods
    • GetProperty()

    Once this is working, you'll want just to set and/or get the value of the property. The GetProperty() method above just returns the PropertyInfo object. To get or set the value you'll have to use the appropriate methods of PropertyInfo.

    I'd not expose the PropertyInfo because it would ruin the magic.

    Better have to extension methods, then:

    T GetPropertyByName<T>(string name);
    SetPropertyByName<T>(string name, T value);
    
    0 讨论(0)
提交回复
热议问题