gpt4 book ai didi

c# - EF Core 2.x - IQueryable 扩展正在客户端而不是数据库进行评估

转载 作者:太空狗 更新时间:2023-10-29 23:35:55 26 4
gpt4 key购买 nike

我有我一直在使用的以下扩展方法。直到最近我才知道 EF Core 2.x 默认情况下执行混合评估,这意味着对于它不知道如何转换为 SQL 的东西,它会从数据库中提取所有内容,然后执行内存中的 LINQ 查询。我已经禁用了这种行为。不管怎样,这是我的扩展方法:

public static class RepositoryExtensions
{
public static IQueryable<T> NonDeleted<T>(this IQueryable<T> queryable) where T : IDeletable
{
return queryable.Where(x => !x.Deleted);
}
}

然后 Entity Framework 抛出异常(因为我此时已将其配置为执行此操作,而不是从数据库中获取所有内容并在本地评估)并显示以下消息:

Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The LINQ expression 'where Not(Convert([x], IDeletable).Deleted)' could not be translated and will be evaluated locally.'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.QueryClientEvaluationWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.

这个扩展方法在很多地方都在使用,所以我宁愿修复它并使其工作(在数据库中进行评估)而不是在许多项目中删除它,然后必须用 .Where(x => !x.Deleted).

有没有其他人遇到过这个并且知道如何制作在数据库中评估的 IQueryable 扩展(在运行时转换为 SQL)?似乎 EF 在将 LINQ 转换为 SQL 时只关注具体类?

更新:其中一条评论要求举个例子。做一些额外的测试,我可以看到这是在应用于从 EF Core 的 .FromSql 返回的 IQueryable 时。如果 .NonDeleted() 直接应用于实体 Organization,它似乎可以正常工作。

// Service layer
public class OrganizationService
{
public IEnumerable<Data.Entities.Organization> GetAllForUser(int? userId)
{
return _repository.GetOrganizationsByUserId(userId.GetValueOrDefault()).NonDeleted();
}
}

//存储层

using PrivateNameSpace.Common.EntityFramework;
using PrivateNameSpace.Data.DbContext;
using PrivateNameSpace.Data.Repos.Interfaces;
using Microsoft.EntityFrameworkCore;
using System.Data.SqlClient;
using System.Linq;

public class OrganizationRepository: Repository<Entities.Organization, int, OrganizationContext>, IOrganizationRepository
{
private const string storedProcedure = "dbo.sproc_organizations_by_userid";

public OrganizationRepository(OrganizationContext context) : base(context)
{
DbSet = Context.Organizations;
}

public IQueryable<Entities.Organization> GetOrganizationsByUserId(int userId)
{
var sql = $"{Sproc} @UserId";
var result = Context.Organizations.FromSql(sql, new SqlParameter("@UserId", userId));
return result;
}
}

最佳答案

虽然您可以将原始 SQL 查询与其他查询表达式组合在一起,例如

var searchTerm = ".NET";

var blogs = context.Blogs
.FromSql($"SELECT * FROM dbo.SearchBlogs({searchTerm})")
.Where(b => b.Rating > 3)
.OrderByDescending(b => b.Rating)
.ToList();

Raw SQL Queries - Composing with LINQ

如果原始 SQL 查询不是简单的 SELECT,则无法执行此操作。无论如何,您将始终过滤存储过程的结果,并且您必须将过程结果加载到服务器上的临时表中以在服务器端应用其他查询运算符。实现起来会很复杂,而且值(value)不大。

关于c# - EF Core 2.x - IQueryable 扩展正在客户端而不是数据库进行评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57327831/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com