LINQ to Entities 不支持在实体框架中调用
本文关键字:框架 调用 实体 to Entities 不支持 LINQ | 更新日期: 2023-09-27 18:32:54
下面是我必须使用表达式的函数,但我认为实体框架不允许这样做。我已经在Linq-to-SQL中使用了这个函数,它正在工作。我也尝试过使用 LinqKit,因为这是我在许多答案中发现的,但错误仍然存在。
public static IList<SelectListItem> From<T>(IQueryable<T> Source, Expression<Func<T, object>> Value, Expression<Func<T, string>> Text)
{
var q = from T item in Source
select new SelectListItem()
{
Text = Text.Compile()((item)),
Value = Value.Compile()((item)).ToString()
};
return q.ToList();
}
当我通过将List<T>
转换为IQueryable
来提供它作为源时,它可以工作。
你可以像这样用 LinqKit 解决问题:
public static IList<SelectListItem> From<T>(
IQueryable<T> Source,
Expression<Func<T, object>> Value,
Expression<Func<T, string>> Text)
{
var q = from T item in Source.AsExpandable()
select new SelectListItem()
{
Text = Text.Invoke(item),
Value = Value.Invoke(item).ToString()
};
return q.ToList();
}
AsExpandable
允许在查询执行之前展开表达式。
当我在客户表上测试上面的代码时,如下所示:
var result =
From(
context.Customers,
x => x.CustomerId,
x => x.Name);
这是在 SQL 服务器上执行的 SQL:
SELECT
[Extent1].[CustomerId] AS [CustomerId],
[Extent1].[Name] AS [Name],
CAST( [Extent1].[CustomerId] AS nvarchar(max)) AS [C1]
FROM [dbo].[Customers] AS [Extent1]
您需要
使用 System.Linq.Expressions
构建整个表达式。
这是一个可以做到这一点的函数(我对类似问题的回答的修改版本表达式来转换 IQueryable
public static class Utils
{
public static IList<SelectListItem> ToSelectList<TSource, TValue>(this IQueryable<TSource> source, Expression<Func<TSource, TValue>> valueSelector, Expression<Func<TSource, string>> textSelector)
{
var itemValue = valueSelector.Body;
if (itemValue.Type != typeof(string))
itemValue = Expression.Call(itemValue, itemValue.Type.GetMethod("ToString", Type.EmptyTypes));
var itemText = textSelector.Body.ReplaceParameter(textSelector.Parameters[0], valueSelector.Parameters[0]);
var targetType = typeof(SelectListItem);
var selector = Expression.Lambda<Func<TSource, SelectListItem>>(
Expression.MemberInit(Expression.New(targetType),
Expression.Bind(targetType.GetProperty("Value"), itemValue),
Expression.Bind(targetType.GetProperty("Text"), itemText)
), valueSelector.Parameters);
return source.Select(selector).ToList();
}
static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterExpressionReplacer { source = source, target = target }.Visit(expression);
}
class ParameterExpressionReplacer : ExpressionVisitor
{
public ParameterExpression source;
public Expression target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == source ? target : base.VisitParameter(node);
}
}
}
请注意,我已经更改了名称,添加了第二个泛型参数以便能够传递未修改的值类型,并使其成为扩展方法,因此可以像这样使用
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
var result = db.Persons.ToSelectList(p => p.Id, p => p.Name);