繁体   English   中英

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

[英]Add new lambda expressions using Expression Tree

我一直在看这里和网上的很多帖子,但它们似乎都没有帮助。

我有一个包含大约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);

谢谢

我正在使用Dynamic Linq源代码 )。 可悲的是,关于如何使用它的文档很少:-)在一个有趣的回旋镖效果中, 有一个“进化”版本 回旋镖效应是因为生成动态类的代码是基于我的一个响应:-)剩下的代码看起来非常漂亮......并且有一套完整的单元测试代码样本! 请注意,第二个库是第一个库的超集,因此您可以将许多示例应用于第一个库! :-)

我正在添加一些静态方法来将动态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 Item2将是一个与int 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);
        }
    }
}

对于需要不同答案的人来说,这是一个简短而简单的答案,但根据我们与@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());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM