根据字符串字段名称选择不同的实体值

时间:2013-09-09 21:40:41

标签: c# linq entity-framework

是否可以选择事先不知道列名的实体的不同属性值 - 由方法作为来自客户端的字符串接收。

出于过滤目的,我想从浏览器向服务器发出一个HTTP POST Ajax请求,该请求将包含字段名称作为密钥,这将作为字符串提供给服务器。

我知道我将不得不手动映射ViewModel和Entity Framework使用的POCO类之间的任何差异,但是可以构造一个没有强类型属性的实体框架查询 - 例如使用反射。 / p>

我可能会尝试实现这一点,其中数据由控制器确定,调用基础存储库的泛型方法,实体类作为类型。这是可能的还是我需要为每个可能的字段构建一个方法?

同样,我应该尝试这样做,还是以字段作为参数构建ADO.NET SQL命令(从ViewModel映射到SQL列名称)?

2 个答案:

答案 0 :(得分:6)

我很确定我最近看到了类似的答案,但我找不到它......

如果您知道实体的类型以及您要选择的属性类型,这很容易:

public IQueryable<TProperty> SelectProperty<TEntity, TProperty>(DbContext context, string propertyName)
    where TEntity : class
{
    var parameter = Expression.Parameter(typeof(TEntity));
    var body = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda<Func<TEntity, TProperty>>(body, parameter);
    var result = context.Set<TEntity>().Select (lambda).Distinct();

    return result;
}

如果无法预测属性的类型,那么构建表达式将更加困难:

public IQueryable SelectProperty<TEntity>(DbContext context, string propertyName)
    where TEntity : class
{
    var entities = context.Set<TEntity>();
    var query = entities.AsQueryable();
    var parameter = Expression.Parameter(typeof(TEntity), "instance");
    var propertyAccess = Expression.Property(parameter, propertyName);
    var projection = Expression.Lambda(propertyAccess, parameter);

    var selectExpression = Expression.Call(
        typeof(Queryable).GetMethods()
                         .First (x => x.Name == "Select")
                         .MakeGenericMethod(new[]{ typeof(TEntity), propertyAccess.Type }),
        query.Expression,
        projection);

    var distinctExpression = Expression.Call(
        typeof(Queryable).GetMethods()
                         .First (x => x.Name == "Distinct")
                         .MakeGenericMethod(new[]{ propertyAccess.Type }),
        selectExpression);

    var result = query.Provider.CreateQuery(distinctExpression);

    return result;
}

答案 1 :(得分:0)

您可以使用Dyanmic Linq(nuget包:System.Linq.Dynamic)执行此操作,以及我甚至不会尝试使用的扩展方法,找到here

示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace dlinq1
{
    class Thing
    {
        public int ID { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var things = new List<Thing>();
            for(int x=0;x<10;x++)
            {
                things.Add(new Thing{ID=x%2}); //0,1,0,1,0,1,0,1,0,1
            }
            var result = things.AsQueryable().Select("ID").Distinct();
            foreach (var r in result)
            {
                Console.WriteLine(r);
            }
            Console.ReadLine(); //produces 0, 1
        }
    }

    public static class DynamicQueryableExtras
    {
        public static IQueryable Distinct(this IQueryable q)
        {
            var call = Expression.Call(typeof(Queryable),
                                       "Distinct",
                                       new Type[] { q.ElementType },
                                       q.Expression);
            return q.Provider.CreateQuery(call);
        }
    }
}

基本上,扩展名适用于自您在调用Distinct之前的前一个表达式以来查询所处的状态。