在C#中创建动态查询

时间:2015-04-10 19:22:25

标签: c# linq

我正在创建一个自定义报告工具,允许用户输入标准列表。

public partial class CustomReportCriteria
    {
        public int Id { get; set; }
        public int ReportId { get; set; }
        public string Operator { get; set; }
        public string CriteriaValue { get; set; }
        public string CriteriaType { get; set; }
        public string CriteriaField { get; set; }
        public string PropertyType { get; set; }

        public virtual CustomReport CustomReport { get; set; }
    }

我需要利用这些字段在我的数据库上创建动态查询。例如:

Select BidYear From FWOBid Where BidYear = 2015
// ^ this would look like this instead
Select CriteriaField From PropertyType Where CriteriaField [Operator] CriteriaValue

但是,我可能并不总是查询同一个表,并且在大多数情况下,查询将需要在其他表上进行连接。

我已经有了where子句的通用方法:

 public static IQueryable<T> Filter<T>(IQueryable<T> query, string propertyName, string propertyValue, string op)
    {
        PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
        return Filter<T>(query, propertyInfo, propertyValue, op);
    }

    public static IQueryable<T> Filter<T>(IQueryable<T> query, PropertyInfo propertyInfo, string propertyValue, string op)
    {
        ParameterExpression e = Expression.Parameter(typeof(T), "e");
        MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
        UnaryExpression c = GetExpressionByType(propertyValue, propertyInfo.PropertyType);

        BinaryExpression b = null;
        if (op == "=")
        {
            b = Expression.Equal(m, c);
        }
        else if (op == "!=")
        {
            b = Expression.NotEqual(m, c);
        }
        else if (op == ">")
        {
            b = Expression.GreaterThan(m, c);
        }
        else if (op == "<")
        {
            b = Expression.LessThan(m, c);
        }

        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(b, e);
        return query.Where(lambda);
    }

我想象的方法是这样的:

foreach (var crit in report.CustomReportCriterias)
            {
                var objectName = crit.PropertyType;
                var value = crit.CriteriaValue;
                var type = crit.CriteriaType;
                var field = crit.CriteriaField;
                var op = crit.Operator;

                // how to dynamically get a generic collection ?
                var queryable = _context.Set<objectName>();
                var results = Filter<objectName>(queryable, field, value, op);
                // would then do joins if needed
            }

但是,我正在努力完成从基于字符串检索数据库中的可查询的初始步骤,然后我迷失了如何在之后加入这些结果。

2 个答案:

答案 0 :(得分:0)

看看https://dynamiclinq.codeplex.com/releases/view/109593。此库使用System.Linq.Dynamic命名空间扩展Linq库,该命名空间为常见查询方法提供基于字符串的重载,因此您可以动态构建基于字符串的过滤和分组标准。另外,我的链接中的一个比通过NuGet提供的版本更好,因为它允许您将Linq语法中的整个查询(包括要检索的记录类型)定义为一个字符串(有关一个示例,请参阅“文档”选项卡;它使用静态typeof表达式来提供类型来解析结果,但您可以反射性地使用Type.MakeGenericType()创建泛型类型。

问题将回到静态定义的类型;一旦你变得动态,你往往必须保持动态,使用GetProperties()枚举数据字段和GetValue / SetValue来操纵它们。有一些技巧,通常需要使用一组具体类型的重载,迫使运行时检查对象的真实类型,然后一旦对象进入其中一个重载,你就会又回到了静止世界。

答案 1 :(得分:0)

使用Entity Framework,您可以直接执行查询,并将结果映射到这样的实体。

var results = db.ExecuteStoreQuery<YourEntity>(
    "SELECT * FROM YourEntities WHERE SomeColumn = @param1", 
    param1);