【问题标题】:Single database call when passing in a list to LINQ将列表传递给 LINQ 时的单个数据库调用
【发布时间】:2017-02-24 10:38:13
【问题描述】:

我收到了一组电子邮件地址,对于每个电子邮件地址,我需要从与该电子邮件地址相关的成员返回 numTotal 和 numActive。

传统上,我会从成员表中查询并过滤成员的电子邮件地址在传入的电子邮件数组中的位置。但是,这只会返回电子邮件地址列表,其中包含成员表中存在的电子邮件的计数。相反,无论成员是否拥有电子邮件地址,我都需要为提供的每个电子邮件地址进行记录。

我的解决方案是遍历电子邮件数组,然后执行子查询。这行得通,我能够得到我需要的东西,但是当我分析调用时,我看到 EF 正在为每个电子邮件地址/子查询运行一个单独的查询。

var result = (from email in emailAddresses
              select new EmailAddressStats {
                 Total = membersQueryable.Any(m => m.Email == email),
                 Active = membersQueryable.Any(m => m.Email == email && m.IsActive)
              }).ToList();

因此,如果我传入 3 个电子邮件地址,我会看到 6 个单独的查询(3 个电子邮件地址 * 2 个子查询)。

我尝试使用 .AsQueryable() 使数组可查询,但仍然得到相同的结果。

理想情况下,我希望 EF 生成如下内容:

SELECT ([totalSubquery]) AS Total,
       ([activeSubquery]) AS Active
FROM ????
WHERE EXISTS ('email1@domain.com', 'email2@domain.com', 'email3@domain.com' )

注意:我使用的是实体框架 4。

【问题讨论】:

  • 我不确定我是否理解你的问题,但你不能使用JOIN 吗? RIGHT JOIN 我想。

标签: c# linq entity-framework-4 linq-to-entities


【解决方案1】:

我没有安装 EF4,但你应该能够像这样只执行一个查询。

List<EmailAddressStats> GetEmailAddressStats(string[] emailAddresses)
{
    var returnList = emailAddresses.Select(e => new EmailAddressStats { Email = e })
                                   .ToList();

    // I don't know what your context is actually called so I'm just calling it MemberDatabaseContext)
    using (var dbContext = new MemberDatabaseContext())
    {
        // Query the database once with a single query to get all of the relevant members
        var membersWithEmailAddress = dbContext.Members.Where(m => emailAddresses.Contains(m.Email))
                                                       .Select(m => new { Email = m.Email, IsActive = m.IsActive })
                                                       .ToList();

        // Update the email stats by analyzing the member info in memory
        foreach (var emailStat in returnList)
        {
            emailStat.Total = membersWithEmailAddress.Count(m => m.Email == emailStat.Email);
            emailStat.Active = membersWithEmailAddress.Count(m => m.Email == emailStat.Email && m.isActive);
        }
    }

    return returnList;
}    

(对不起,这是用 Fluent 语法而不是 Query Expression 语法,但我只知道如何用 Fluent 语法做到这一点)

【讨论】:

  • 这将只包括电子邮件地址在传入列表中的成员。我需要记录每个传入的电子邮件地址,无论是否有人拥有它,这就是为什么我要查看电子邮件列表而不是过滤的成员列表。
  • @AndrésNava-.NET 在阅读您的评论并更仔细地重新阅读您的问题后,我更新了我的答案。现在它应该只执行一个数据库查询,然后在内存中执行“join”操作。如果这仍然不能回答您的问题,您能否分享更多围绕数据库调用的代码,以便我更清楚地了解您正在尝试做什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-26
  • 2021-12-29
  • 2021-12-01
  • 2017-06-01
  • 1970-01-01
  • 2013-10-15
相关资源
最近更新 更多