Linq调用表值函数时在FromSqlInterpolated上的位置

问题描述 投票:0回答:2

我有一个名为tf_ArtikelSearch的表值函数,该函数将语言代码作为输入。我可以使用[

作为SQL查询成功执行它
SELECT *
FROM tf_ArtikelSearch('D')
WHERE PackungId = 38673

现在,我想使用Linq在其中生成相同(或相似)查询。但是当我运行下面的代码

public async Task<IEnumerable<ArtikelSearchResult>> Search(ArtikelSearchFilter filter)
{
    var query = Set.FromSqlInterpolated($"dbo.tf_ArtikelSearch ({filter.SprachCode})")
                   .Where(result => result.PackungId == 38673);

    return await query.ToListAsync();
}

我收到以下异常:


System.InvalidOperationException : FromSqlRaw or FromSqlInterpolated was called with non-composable SQL and with a query composing over it. Consider calling `AsEnumerable` after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client side.
   at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitFromSql(FromSqlExpression fromSqlExpression)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
   at EntityFrameworkCore.TemporalTables.Query.AsOfQuerySqlGenerator.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.<VisitSelect>b__18_1(TableExpressionBase e)
   at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.GenerateList[T](IReadOnlyList`1 items, Action`1 generationAction, Action`1 joinAction)
   at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitSelect(SelectExpression selectExpression)
   at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.GetCommand(SelectExpression selectExpression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalCommandCache.GetRelationalCommand(IReadOnlyDictionary`2 parameters)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Refdata.SAI.Data.Repositories.ArtikelSearchRepository.Search(ArtikelSearchFilter filter) in C:\dev\Refdata.SAI\Source\Refdata.SAI.Data\Repositories\ArtikelSearchRepository.cs:line 27
   at Refdata.SAI.Data.Tests.Integration.ArtikelSearchResultRepositoryTests.ArtikelSearch_OK_Test() in C:\dev\Refdata.SAI\Source\Refdata.SAI.Data.Tests.Integration\ArtikelSearchResultRepositoryTests.cs:line 21
--- End of stack trace from previous location where exception was thrown ---

请注意,没有where子句的EF查询可以正常工作。我是在做错什么还是EF core 3.1无法做到这一点?

c# linq linq-to-sql ef-core-3.1
2个回答
0
投票

简而言之-您不能(至少对于SqlServer而言)。 docs的Composing with LINQ部分指出:

使用LINQ进行组合要求您的原始SQL查询必须是可组合的,因为EF Core会将提供的SQL视为子查询。可以组成的SQL查询以SELECT关键字开头。

SQL Server不允许通过存储过程调用进行组合,因此,任何尝试将附加查询运算符应用于此类调用的尝试都将导致无效的SQL。在FromSqlRaw或FromSqlInterpolated方法之后立即使用AsEnumerable或AsAsyncEnumerable方法,以确保EF Core不会尝试对存储过程进行组合。

因此,您需要获取所有数据并在客户端进行过滤,或者创建将接受PackungId作为参数的新存储过程,或为此创建视图/表值函数。


0
投票

根据Raw SQL Queries,您不能那样做>

SQL Server不允许通过存储过程调用进行组合,因此任何 尝试将其他查询运算符应用于此类调用将导致 在无效的SQL中。正确使用AsEnumerable或AsAsyncEnumerable方法 在FromSqlRawFromSqlInterpolated方法之后,以确保EF Core不会尝试组成存储过程。

您可以从数据库中获取数据,然后按如下所示在内存中添加Where条件:

var searchResult = Set.FromSqlInterpolated($"dbo.tf_ArtikelSearch ({filter.SprachCode})").ToList();
var filteredResult = searchResult.Where(result => result.PackungId == 38673);

或者您可以通过添加新的tf_ArtikelSearch参数来更新PackungId功能。

© www.soinside.com 2019 - 2024. All rights reserved.