问题在于 Linq To Entities 不支持已编译的表达式,并且您已编译表达式并尝试调用它们。但是 LINQ 试图将它们解析为表达式并将它们转换为 SQL 代码,但它做不到。
并且你想将text 和value 作为不同的参数传递,所以你不能将它们组合起来。
你可以这样做:
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 })