繁体   English   中英

如何使用 EF 优化此查询?

[英]How to optimize this query with EF?

我正在尝试使用 EF 优化此查询。 这是我一开始的疑问。

var result = new List<string>();

_dbContext.signumid_organization.ToListAsync().Result.ForEach(organization =>
{
    if (CalculateDifferenceBetweenEntriesAndConsummations(null, organization.Id).Result > threshold)
    {
        return;
    }

    if (!string.IsNullOrEmpty(organization.Admin))
    {
        result.Add(organization.Admin);
    }
});

return Task.FromResult(result);

现在我尝试优化它并立即拥有它

return Task.FromResult(_dbContext.signumid_organization
    .Where(organization => !string.IsNullOrEmpty(organization.Admin) &&
                            CalculateDifferenceBetweenEntriesAndConsummations(null, organization.Id).Result <=
                            threshold).Select(x => x.Admin).ToList());

但问题是我抛出了一个异常,它无法翻译查询。 你对我的例外有什么解决办法吗? 或者也许是另一种查询方法?

这是一个例外:

System.InvalidOperationException: LINQ 表达式 'DbSet() .Where(o => !(string.IsNullOrEmpty(o.Admin)) && ProductProvisioningRepository.CalculateDifferenceBetweenEntriesAndConsummations( phoneNumber: null, organizationId: (int?)o.Id).Result < = __p_0)' 无法翻译。 附加信息:方法“Signumid.ProductProvisioning.ProductProvisioningRepository.CalculateDifferenceBetweenEntriesAndConsummations”的翻译失败。 如果此方法可以映射到您的自定义函数,请参阅https://go.microsoft.com/fwlink/?linkid=2132413了解更多信息。 方法“Signumid.ProductProvisioning.ProductProvisioningRepository.CalculateDifferenceBetweenEntriesAndConsummations”的翻译失败。 如果此方法可以映射到您的自定义函数,请参阅https://go.microsoft.com/fwlink/?linkid=2132413了解更多信息。 以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。 有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

这是 CalculateDifferenceBetweenEntriesAndConsummations 所做的:

if (organizationId != null)
{
    return await _dbContext.signumid_credit_operation
                .Where(x => x.OrganizationId == organizationId && x.OperationType == OperationType.Purchase)
                .SumAsync(x => x.Amount)
            - await _dbContext.signumid_credit_operation
                .Where(x => x.OrganizationId == organizationId && x.OperationType == OperationType.Consummation)
                .SumAsync(x => x.Amount);
}

您在数据库和查询数据库的应用程序中混合工作。

.ToList[Async()]之前的事情发生在数据库中,之后的事情发生在应用程序中。

以下是一些选项:

  1. 在数据库中创建一个数据库函数CalculateDifferenceBetweenEntriesAndConsummations ,并在linq查询中使用
  2. 不要使用函数并在Where中进行计算 - 如果计算足够简单可以转换为 SQL,这将起作用。 调用函数时具有.Result的片段表明它是异步的,这使事情变得复杂,但也许它不必是异步的。
  3. 从数据库中获取所有记录,然后应用CalculateDifferenceBetweenEntriesAndConsummations - 你最初拥有的
  4. 用 SQL 编写查询并使用它而不是使用 EF。

边点:

return Task.FromResult(_dbContext.signumid_organization
            .Where(Select(x => x.Admin).ToList());

应该很可能是

await _dbContext.signumid_organization
            .Where(Select(x => x.Admin).ToListAsync();

这同样适用于_dbContext.signumid_organization.ToListAsync().Result. 这应该是`(等待_dbContext.signumid_organization.ToListAsync())。


在CalculateDifferenceBetweenEntriesAndConsummations 发布后更新。

这 3 个查询可以在 SQL 中合并为一个,看起来这样:

SELECT 
 name
FROM signumid_organization org
JOIN signumid_credit_operation co on co.OrganizationId = org.Id
WHERE co.OperationType in (number_for_Purchase, number_for_Consummation)
GROUP BY org.Id
HAVING  
   (  SUM(CASE co.OperationType = number_for_Purchase THEN Amount ELSE 0 END)
    - SUM(CASE co.OperationType = number_for_Consummation THEN Amount ELSE 0 END)
   > threshold -- or '<=', I'm not sure

您可以完成此查询,然后从您的代码中执行此查询,或者完成此查询并将其转换为 LINQ。

好吧,一切都可以在服务器上完成:

var result = await _dbContext.signumid_credit_operation
    .Where(x => !string.IsNullOrEmpty(x.Admin))
    .GroupBy(x => new { x.OrganizationId, organization.Admin })
    .Select(g => new
    {
        g.Key.OrganizationId,
        g.Key.Admin,
        Difference = g.Sum(x => x.OperationType == OperationType.Purchase ? x.Amount : 0) 
                    - g.Sum(x => x.OperationType == OperationType.Consummation ? x.Amount : 0)
    })
    .Where(x => x.Difference <= 100)
    .Select(x => x.Admin)
    .ToListAsync();

return result;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM