簡體   English   中英

LINQ to Entities不支持在實體框架中調用

[英]LINQ to Entities Does not Support Invoke in Entity Framework

下面是我必須使用表達式的函數,但是我認為實體框架不允許這樣做。 我已經在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來提供List<T>作為源時,它可以工作。

您可以使用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 Server上執行的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構建整個表達式。

這是執行此操作的函數(我對類似問題Expression的答案的修改版本, 以將IQueryable <t> int List <SelectListItem>轉換為 ):

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM