簡體   English   中英

在 Entity Framework Core 中擴展 DbFunctions?

[英]Extending DbFunctions in Entity Framework Core?

使用 .NET Core 3.1.1 和 Entity Framework Core 3.1.1,我有:

var query = from user in context.Users
            join userRole in userRoleView on user.Id equals userRole.UserId into gj
            from p in gj.DefaultIfEmpty()
            select new
                   {
                        user.Id,
                        user.UserName,
                        RoleName = p.Rolename,
                        user.CreatedUtc,
                        user.ModifiedUtc,
                  };

if (!String.IsNullOrWhiteSpace(conditions.Keyword))
{
    query = query.Where(d => EF.Functions.Like(d.UserName, "%" + conditions.Keyword + "%"));
}

這運行良好,然后我想要EF.Functions.Contains(d.UserName, conditions.Keyword) ,所以我寫了一個擴展:

public static class DbFunctionsExtensions
{
    public static bool Contains(this DbFunctions _, string matchExpression, string keyword)
    {
        return _.Like(matchExpression, "%" + keyword + "%");
    }
}

但是,運行時

query.Where(d => EF.Functions.Contains(d.UserName, conditions.Keyword))

我得到這個例外:

System.InvalidOperationException ... 無法翻譯。

要么以可翻譯的形式重寫查詢,要么通過插入對AsEnumerable()AsAsyncEnumerable()ToList()ToListAsync()的調用顯式切換到客戶端評估。 有關詳細信息,請參閱https://go.microsoft.com/fwlink/?linkid=2101038

來源=Microsoft.EntityFrameworkCore

StackTrace:在 Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.g__CheckTranslated|8_0(ShapedQueryExpression 翻譯,<>c__DisplayClass8_0&)
在 Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
在 Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
在 System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor 訪問者)
在 System.Linq.Expressions.ExpressionVisitor.Visit(表達式節點)
在 Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
在 Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) 在 System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitorvisitor) 在 System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) 在 Microsoft.ExpressEntityQueryVisitorTranslationCore。 .VisitMethodCall(MethodCallExpression methodCallExpression) 在 Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) 在 System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitorvisitor) 在 Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) 在 System.Linq.Expressions.ExpressionVisitor.node .EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async) at Microsoft.EntityFrameworkCore.Query。 Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase 數據庫、表達式查詢、IModel 模型、布爾異步)在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0 1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](對象 cacheKey,Func 1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func 1 編譯1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.GetEnumerator() 在 System.Collections.Generic.LargeArrayBuilder 1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.AddRange(IEnumerable 1 items) at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable 1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable 1 source) at APS.WebPos.DAL.Se archOperations.GetActivePeopleByKeyword(String keyword) in C:\\VSProjects\\ApsCloudTrunk\\APS.WebPos.DALCore\\SearchOperations.cs:line 96 at APS.WebPos.WebApi.Controllers.SearchController.GetActivePeopleByKeyword(String keyword) in C:\\VSProjects\\ApsCloudTrunk \\APS.WebPos.WebApiCore\\Controllers\\SearchController.cs:line 25 at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper)映射器、ObjectMethodExecutor 執行器、對象控制器、Object[] 參數)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() 在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

是否可以使用 Entity Framework Core 在應用程序中擴展 DbFunctions,並在 LINQ 中使用它? 如何?

評論:

String.Contains()在 EF Core 查詢中區分大小寫,但在 SQL 中轉換為 LIKE 的 EF 中不區分大小寫。

您可以使用簡單的 one -> context.Users.Where(x => (conditions.Keyword == null || x.UserName.Contains(conditions.Keyword)))。 如果conditions.Keyword 為空,則跳過過濾器。

var query = from user in context.Users.Where(x => (conditions.Keyword == null || x.UserName.Contains(conditions.Keyword)))
                        join userRole in userRoleView
                        on user.Id equals userRole.UserId into gj
                        from p in gj.DefaultIfEmpty()
                        select new
                        {
                            user.Id,
                            user.UserName,
                            RoleName = p.Rolename,
                            user.CreatedUtc,
                            user.ModifiedUtc,
                        };

Where方法的參數是一個Expression ,它的主體在將查詢轉換為 SQL 時無關緊要。 這就是為什么你會得到一個例外。

要使其工作,您需要動態構造一個表達式。

public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> prop, string keyword)
{
    var concatMethod = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
    return Expression.Lambda<Func<T, bool>>(
        Expression.Call(
            typeof(DbFunctionsExtensions),
            nameof(DbFunctionsExtensions.Like),
            null,
            Expression.Constant(EF.Functions),
            prop.Body,
            Expression.Add(
                Expression.Add(
                    Expression.Constant("%"),
                    Expression.Constant(keyword),
                    concatMethod),
                Expression.Constant("%"),
                concatMethod)),
        prop.Parameters);
}

然后在您的查詢中使用它

if (!String.IsNullOrWhiteSpace(conditions.Keyword))
{
    query = query.Where(Like<User>(d => d.UserName, conditions.Keyword));
}

PS 問題的標題方式看起來接近什么標量函數映射,但它不適用於 LIKE 子句的情況。

暫無
暫無

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

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