Scenario

我有这个代码(简化):

var query = _context.Products
                    .Where(x => x.IsActive)
                    .Select(x => new ProductDto 
                                 {
                                     Id = x.Id,
                                     Name = x.Name,
                                     Description = GetDescription(x)
                                 });

// Building predicates (using LinqKit)
var predicate = PredicateBuilder.New<T>();

query = query.Where(predicate);

var count = await query.CountAsync();
var list = await query.ToListAsync();

当我按ID和姓名进行过滤时,它会起作用.当我想按Description进行筛选时,问题就出现了,例如:

query = query.Where(x => x.Description.Contains("winter"));

这里抛出了一个异常--Linq无法将其转换为可理解的SQL.

Question

你觉得我能处理好吗?这就是我如何构建我的过滤/排序等,我想保持这种状态如何根据使用C#方法但无法转换为SQL的属性进行筛选/排序?

What I tried

在读完这Efficient Querying EF Core本书后,我有了一个 idea ,也许这是一条可行的道路.

我试着这样做:

var predicate = PredicateBuilder.New<T>();

var enumerable = query.AsEnumerable();

enumerable = enumerable.Where(predicate);

// I convert it back to Queryable to use things such as 
// Take() and Skip() hoping it will be translated into SQL
query = enumerable.AsQueryable();

// Here I lost the ability to use "Async"
var count = query.Count();
var list = query.ToList();

看上go 挺管用的.我失go 了在SQL级别上进行过滤的能力(但我可能能够区分在哪个阶段应用哪些过滤器),但我不确定它是如何工作的.

我想我理解缓冲和流之间的区别--在这里我不会将所有结果加载到内存中--我希望发生流.在判断数据库调用时--只进行一次调用(.Count().ToList()),这听起来不错.

这是解决这个问题的有效方法吗?在.AsEnumerable()岁之后,过滤到底是如何工作的?如果Linq既不将GetDescription(x)加载到内存中,也不向数据库发送请求,它如何知道如何处理GetDescription(x)

// Edit for more context:
I might have simplified too much, sorry about that. My GetDescription method looks like this:

public static string GetDescription(int productType)
{
    switch (productType)
    {
        case 0:
            return ProductTypeEnum.Value1.GetDescription();
        case 1:
            return ProductTypeEnum.Value2.GetDescription();
    }

    return string.Empty;
}

我在查询中这样使用它:

Description  = x.ProductType != null ? GetDescription(x.ProductType) : string.Empty

Post-thoughts after resolving the issue
I misunderstood how queries are translated. The fact misled me, that without filtering by problematic property - everything worked fine. I thought it meant that it is evaluated on the server side and translated into SQL. What was happening was that this property was marked to be evaluated on the client side, once the records were fetched.

如果你的查询不能被转换成SQL -首先要确保查询写得很好,因为它可能不是.

推荐答案

我想我理解缓冲和流媒体之间的区别

这里的区别是客户端判断和服务器端判断.

这是解决这个问题的有效方法吗?

可以说-不是.

.AsEnumerable()岁之后,过滤到底是如何工作的?

之前的一切将被转换为SQL并在数据库端执行,之后的一切将在客户端(在内存中)处理,即对于Count,所有匹配的行将被提取到内存中,GetDescription将被调用,然后将进行过滤,然后对项目进行计数.然后,您将再次获取并过滤ToList的所有相同项.请注意,EF Core可以在最终投影(即最后Select)中调用自定义函数,而无需移动到客户端.如果投影属性是通过可翻译代码创建的(即,不使用GetDescription等客户端函数的代码),EF Core还可以处理对投影属性的过滤.还要注意,GetDescription(x)应该导致获取表的所有列.

如果Linq既不将GetDescription(X)加载到内存中,也不向数据库发送请求,它如何知道如何处理GetDescription(X)呢?

将使用Linq-to-Object,它将只调用该方法

判断数据库调用时-仅进行单个调用

我想知道你是怎么做到的,你看到了什么问题.try 启用simple logging for EF Core并判断日志(log).

你能做什么很大程度上取决于GetDescription.你可以提供一个user defined function mapping,这应该使它可以翻译.或者做一些类似的事情:

var query = _context.Products
   .Where(x => x.IsActive)
   .Where(x => x.DescriptionPartColumn1.Contains("winter") 
       || x.DescriptionPartColumn1.Contains("winter"))
   .Select(x => new ProductDto ...)

另外,我还建议你go 看看:

UPD

只需内联GetDescription函数:

var query = _context.Products
   .Where(x => x.IsActive)
   .Select(x => new ProductDto
   {
       //...
       Description = x.ProductType == 0
           ? "This is one Desc"
           :  x.ProductType == 1 
                 ? "This is two Desc" 
                 : string.Empty
   })

Csharp相关问答推荐

使用GeneratedComInterfaceProperty的.NET 8 COM类对于VB 6/SYS或ALEViewer不可见

MongoDB将JS查询转换为C#的问题

如何从泛型方法返回一个可为空的T,其中T:notnull?

Select Many和默认IfEmpty内部Select Many错误工作

在一个模拟上设置一个方法,该模拟具有一个参数,该参数是一个numc函数表达式

查找表中的模式

Appsettings.json未加载.Net 8 Blaazor Web程序集

Rx.Net窗口内部可观测数据提前完成

C#普罗米修斯指标

是否可以将Collectionview中的数组与ObservableCollection绑定?

C#按名称从类获取属性值类型<;t>;,我需要反射吗?

我可以查看我们向应用程序洞察发送了多少数据吗?

如何在同一成员上组合[JsonPropertyName]和[ObservableProperty]?

如何在单击按钮后多次异步更新标签

Autofac -动态实例化:手动传递构造函数

如何将 colored颜色 转换为KnownColor名称?

无法向Unity注册Microsoft Logger

如何读取TagHelper属性的文本值?

Azure队列触发器未使用隔离的工作进程执行

使用';UnityEngineering.Random.Range()';的IF语句仅适用于极高的最大值