【问题标题】:Entity to DropDownListItem using Lambda expressions in method实体到 DropDownListItem 在方法中使用 Lambda 表达式
【发布时间】:2014-11-24 21:25:33
【问题描述】:

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

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

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)

【问题讨论】:

    标签: c# linq lambda expression func


    【解决方案1】:

    问题在于 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 })
    

    【讨论】:

    • 您好,我收到了这样的错误参数“x”未绑定在指定的 LINQ to Entities 查询表达式中。感谢您的帮助。
    • 嗨。嗯你是对的。我已经用更新的ExpressionReplacer 更新了答案,并轻轻更改了ToDropDownList 方法。我用 EF 在本地检查了它,它工作正常。
    猜你喜欢
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多