使用方法中的Lambda表达式实现DropDownListItem

时间:2014-11-24 21:25:34

标签: c# linq lambda expression func

我有实体,例如CategoryEntity,RubricEntity,CityEntity等 我需要显示这些实体的下拉列表。此实体具有不同的属性。 所有这些我需要转换为DropDownListItem以显示为下拉列表,所以我想我可以使用这样的方法来处理数据库,但我得到了异常

LINQ表达式节点类型' Invoke' LINQ to Entities不支持。

public static IQueryable<DropDownListItem> ToDropDownList<TSource>(IQueryable<TSource> query, Expression<Func<TSource, long>> value, Expression<Func<TSource, string>> text)
        {
            var valueLambda = value.Compile();
            var textLambda = text.Compile();

            return query.Select(x => new DropDownListItem
            {
                Value = (long) valueLambda(x),
                Text = (string) textLambda(x)
            });
        }

我认为我可以使用类似的东西,但不知道如何使用表达式和lambda来制作它。

因此我想要像

这样的东西
ToDropDownList2<RubricEntity>(_service.RubricAsQueryable(), x => x.Id, x => x.DisplayName)

1 个答案:

答案 0 :(得分:0)

问题是Linq To Entities不支持编译表达式,并且您编译了两个表达式并尝试调用它们。但是LINQ试图将它们解析为表达式并将它们转换为SQL代码,而它却无法做到。 并且您希望将textvalue作为不同的参数传递,因此您无法将它们组合在一起。

你可以这样做:

public static IQueryable<DropDownListItem> ToDropDownList<TSource>(IQueryable<TSource> query, Expression<Func<TSource, DropDownListItem>> value)
{
    return query.Select(value);
}

ToDropDownList<RubricEntity>(_service.RubricAsQueryable(), x => new DropDownListItem() { Value = x.Id, Text = x.DisplayName });

但就我而言,它没有多大意义......

如果您仍想将它们作为单独的参数传递,那么您可以尝试在运行时将它们组合起来,如下所示:

public static IQueryable<DropDownListItem> ToDropDownList<TSource>(IQueryable<TSource> query, Expression<Func<TSource, long>> value, Expression<Func<TSource, string>> text)
{
    Expression<Func<TSource, DropDownListItem>> func = x => new DropDownListItem
    {
        Value = 1,
        Text = "1"
    };


    var replacer = new ExpressionReplacer<TSource>()
                   {
                       Text = text,
                       Value = value,
                       Parameter = func.Parameters[0] // we will take X parameter

                   };
    var convertedFunc = replacer.Visit(func) as Expression<Func<TSource, DropDownListItem>>;

    return query.Select(convertedFunc);
}


private class ExpressionReplacer<TSource> : ExpressionVisitor
{
    public Expression<Func<TSource, long>> Value { get; set; }
    public Expression<Func<TSource, string>> Text { get; set; }
    public ParameterExpression Parameter { get; set; }

    protected override Expression VisitConstant(ConstantExpression node)
    {
        if (node.Type == typeof(long))
            return this.Visit(Value.Body);
        if (node.Type == typeof(string)) 
            return this.Visit(Text.Body);
        return base.VisitConstant(node);
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        // we will replace all usage to X. it has the same type, but it isn't linked to expiression
        return Parameter; 
    }
}

ToDropDownList<RubricEntity>(_service.RubricAsQueryable(), x => x.Key, x => x.Value);

基本上我们只是使用常量值创建存根表达式,然后根据类型到参数中的表达式替换常量值。然后将替换的表达式发送给Select方法,因此最终表达式将类似于:

Select(x => new DropDownListItem() { Value = x.Id, Text = x.DisplayName })