使用表达式树添加新的lambda表达式

时间:2017-03-14 10:47:43

标签: c# sql-server linq lambda expression-trees

我一直在网上和网上看过很多帖子,但似乎都没有帮助。

我有一张包含大约200万条记录的表格,它有超过200列。

一个简单的Web服务允许用户从表中提取特定数量的列,用户可以选择要提取的列。

结果需要是逗号分隔值的字符串,因此我的查询需要拉取请求的列并返回一个连接字符串。

我使用ADO.NET和纯SQL查询完成了这项工作,但是我被要求在实体框架中执行此操作。

这是我已经做过的事情。

我将请求的列列表作为字符串数组。

以下是我的询问,不确定这是否是最好的解决方案或想法,因此我在这里寻求帮助。

var valueList2 = ctx.mytable.Where(x => x.pcds == comValue).Select(x => new{temp = x.column1 +", "+ x.column2}).Select(x => x.temp).ToList();

上面给出了用逗号分隔的两列的字符串,我只需要以某种方式将我的列名列推送到它的lambda部分。

我做了以下但后来意识到它只适用于非匿名类的特定类型,我也无法弄清楚如何将它用于多列并且不会使它如此复杂。

var createdType = typeof(mytable);
var Param = Expression.Parameter(typeof(string), "pr");
var obj = Expression.New(createdType);
var ValueProperty = createdType.GetProperty("long");
var ValueAssignment = Expression.Bind(ValueProperty, Param);
var memberInit = Expression.MemberInit(obj, ValueAssignment);
var lm = Expression.Lambda<Func<string, mytable>>(memberInit, Param);

谢谢

2 个答案:

答案 0 :(得分:1)

我正在使用Dynamic Linqsource code)。可悲的是,关于如何使用它的文档很少:-)在一个有趣的回旋镖效果中,there is an "evolved" version。回旋效应是因为用于生成动态类的代码基于我的一个响应:-)其余的代码似乎非常漂亮......并且有一个full suit of unit tests with code samples!!!请注意,这第二个库是一个超集第一个库,所以你可以在第一个库中应用很多例子! : - )

我正在添加一些静态方法来将Dynamic Linq查询的结果转换为IEnumerable<object[]> ....示例代码:

using (var ctx = new Model1())
{
    var result = ctx.MyTable
        .Take(100)
        .SimpleSelect(new[] { "ID", "Col1", "Col2" })
        .ToObjectArray();

    foreach (var row in result)
    {
        Console.WriteLine(string.Join(", ", row));
    }
}

更复杂的例子:

var columnsNames = new[] { "SomeNullableInt32", "SomeNonNullableDateTimeColumn" };

// One for each column!
var formatters = new Func<object, string>[]
{
    x => x != null ? x.ToString() : null,
    x => ((DateTime)x).ToShortDateString()
};

var result = ctx.MyTable.Take(100).SimpleSelect(columnsNames).ToObjectArray();

foreach (var row in result)
{
    var stringRow = new string[row.Length];

    for (int i = 0; i < row.Length; i++)
    {
        stringRow[i] = formatters[i](row[i]);
    }

    Console.WriteLine(string.Join(", ", stringRow));
}

这些类......一个(SimpleSelect)生成动态SQL选择,并“匿名”字段名称。我这样做是因为对于每种类型的返回,Dynamic Linq将在运行时生成一个类。在程序结束之前,不会卸载此类。通过匿名列(我将它们重命名为Item1Item2Item3 ...),我增加了重用同一类的可能性。请注意,不同类型的列将生成不同的类! (int Item1, string Item2int Item1, DateTime Item2)不同,其他(ToObjectArray)返回IEnumerable<object[]>,更容易解析。

public static class DynamicLinqTools
{
    private static ConcurrentDictionary<Type, Func<object, object[]>> Converters = new ConcurrentDictionary<Type, Func<object, object[]>>();

    public static IQueryable SimpleSelect(this IQueryable query, string[] fields)
    {
        // With a little luck, "anonymizing" the field names we should 
        // reduce the number of types created!
        // new (field1 as Item1, field2 as Item2)
        return query.Select(string.Format("new ({0})", string.Join(", ", fields.Select((x, ix) => string.Format("{0} as Item{1}", x, ix + 1)))));
    }

    public static IEnumerable<object[]> ToObjectArray(this IQueryable query)
    {
        Func<object, object[]> converter;

        Converters.TryGetValue(query.ElementType, out converter);

        if (converter == null)
        {
            var row = Expression.Parameter(typeof(object), "row");

            // ElementType row2;
            var row2 = Expression.Variable(query.ElementType, "row2");

            // (ElementType)row;
            var cast = Expression.Convert(row, query.ElementType);

            // row2 = (ElementType)row;
            var assign = Expression.Assign(row2, cast);

            var properties = query.ElementType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(x => x.CanRead && x.GetIndexParameters().Length == 0)
                .ToArray();

            // (object)row2.Item1, (object)row2.Item2, ...
            var properties2 = Array.ConvertAll(properties, x => Expression.Convert(Expression.Property(row2, x), typeof(object)));

            // new object[] { row2.Item1, row2.Item2 }
            var array = Expression.NewArrayInit(typeof(object), properties2);

            // row2 = (ElementType)row; (return) new object[] { row2.Item1, row2.Item2 }
            var body = Expression.Block(typeof(object[]), new[] { row2 }, assign, array);

            var exp = Expression.Lambda<Func<object, object[]>>(body, row);
            converter = exp.Compile();

            Converters.TryAdd(query.ElementType, converter);
        }

        foreach (var row in query)
        {
            yield return converter(row);
        }
    }
}

答案 1 :(得分:0)

对于需要不同答案的人来说,这是一个简短而简单的答案,但根据我们与@xanatos的讨论,它不是最好的,因为它还会返回所有需要在删除之前切断的列。字符串列表。

List<string> valueList = new List<string>();
using (var ctx = new DataEntities1())
{
    var query = ctx.myTable.Where(x => x.pcds == scode).SingleOrDefault();

    foreach (var item in columnsArray)
    {
        valueList.Add(typeof(myTable).GetProperty(onsColumns[Convert.ToInt32(item)]).GetValue(query).ToString());
    }
}
相关问题