LINQ to Entities - Addressing class properties wit

2020-03-31 07:59发布

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 write a LINQ to Entities query that can filter by using the strongly-typed property SampleId. For example:

    db.Cases.Where(x=>targetlist.Contains(x.SampleId))

where targetlist is a list of items from the filter.

So, in effect, is there a way to write a query such that "SampleId" can directly translate to Case.SampleId?

I have tried reflection and made use of the GetProperty and GetValue and LINQ to Entities does not like it.

Any suggestions will be much appreciated!


EDIT (by pid for original poster srinaik2020):

@zaitsman: this is the code posted in an comment further below and is the actual resolution of the problem, based on the accepted answer.

public static class MyExtensions
{
    public static string GetPropertyByName(this CaseV case1, string name)
    {
        var x = typeof (CaseV).GetProperty(name).GetValue(case1);

        if (x != null)
        {
            return x.ToString();
        } else {
            return "none";
        }
    }
}

2条回答
家丑人穷心不美
2楼-- · 2020-03-31 08:09

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:

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);
查看更多
疯言疯语
3楼-- · 2020-03-31 08:12

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);
查看更多
登录 后发表回答