【问题标题】:RavenDB IEnumerable vs ListRavenDB IEnumerable 与列表
【发布时间】:2012-01-09 02:43:56
【问题描述】:

我有一些我不理解的行为。我正在使用 RavenDB,并且我正在为每个工作单元使用一个会话:当一个逻辑类调用 RavenDB 数据访问层 (DAL) 时,会创建一个新会话。在 DAL 中,可以调用其他 DAL 类和方法,但只会使用一个会话。

我不明白的部分是在下面的 GetMostRecentByStartTime() 方法中使用 IEnumerable 和 List 之间的区别。在那个方法中,使用 List 就像显示的那样,这是我的输出:

使用列表:
关闭会话前的请求数:2
关闭会话前的请求数:4
会议结束前的请求数:6
关闭会话前的请求数:7

注意:会话实际上并不是每次都关闭;只有在最后一次之后。我们只在最初调用的 DAL 方法完成后关闭会话。

现在,如果我用 IEnumerable 替换 List 的每个实例(这是我所做的唯一更改),我会得到以下输出:

使用 IEnumerable:
关闭会话前的请求数:2
会议结束前的请求数:3
关闭会话前的请求数:4
关闭会话前的请求数:27

为什么不一样?

另一个问题是,当我在我的应用程序中添加新的 InstallationSummary 对象时,使用 IEnumerable 方法请求计数会增加。我不明白为什么。当我使用 List 方法时,请求计数保持不变,即使添加了更多 InstallationSummary 对象。谁能解释一下?

public IEnumerable<InstallationSummary> GetMostRecentByStartTime(int numberToRetrieve)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    try
    {
        return ExecuteQuery<IEnumerable<InstallationSummary>>(() =>
        {
            List<InstallationSummary> installationSummaries =
                QueryAndCacheEtags(session => session.Advanced.LuceneQuery<InstallationSummary>()
                .Include(x => x.ApplicationServerId)
                .Include(x => x.ApplicationWithOverrideVariableGroup.ApplicationId)
                .Include(x => x.ApplicationWithOverrideVariableGroup.CustomVariableGroupId)
                .OrderByDescending(summary => summary.InstallationStart)
                .Take(numberToRetrieve)).Cast<InstallationSummary>().ToList();

            List<string> appServerIds = (from item in installationSummaries select item.ApplicationServerId).ToList();
            List<string> appIds = (from item in installationSummaries select item.ApplicationWithOverrideVariableGroup.ApplicationId).ToList();
            List<string> groupIds = (from item in installationSummaries select item.ApplicationWithOverrideVariableGroup.CustomVariableGroupId).ToList();

            List<ApplicationServer> appServers = new ApplicationServerData().GetByIds(appServerIds).ToList();
            List<Application> apps = new ApplicationData().GetByIds(appIds).ToList();
            List<CustomVariableGroup> groups = new CustomVariableGroupData().GetByIds(groupIds).ToList();

            foreach (InstallationSummary summary in installationSummaries)
            {
                summary.ApplicationServer = appServers.Where(server => server.Id == summary.ApplicationServerId).FirstOrDefault();

                summary.ApplicationWithOverrideVariableGroup.Application =
                    apps.Where(app => app.Id == summary.ApplicationWithOverrideVariableGroup.ApplicationId).FirstOrDefault();

                if (summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupId == null) { continue; }

                summary.ApplicationWithOverrideVariableGroup.CustomVariableGroup =
                    groups.Where(group => group.Id == summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupId).FirstOrDefault();
            }

            return installationSummaries;
        });
    }
    finally
    {
        stopwatch.Stop();
        Debug.WriteLine("InstallationSummaryData.GetMostRecentByStartTime(): " + stopwatch.ElapsedMilliseconds);
    }
}

这里是调用上述方法的地方:

protected T ExecuteQuery<T>(Func<T> func)
{
    if (func == null) { throw new ArgumentNullException("func"); }

    try
    {
        return func.Invoke();
    }
    finally
    {
        Debug.WriteLine("Number of requests just before closing session: " + _session.Advanced.NumberOfRequests);
        CloseSession();
    }
}

【问题讨论】:

    标签: linq ienumerable ravendb


    【解决方案1】:

    首先,如果您将所有 IList 换出并替换为 IEnumerables,这并不是一个小改动。主要区别在于您可以使用 IEnumerables 获得延迟执行,而在使用 IList 时总是有急切执行。如果您不知道这种差异,这可能会导致很多问题。

    在您的情况下,差异的原因是延迟执行和错误使用 RavenDB 的 .Include&lt;T&gt;() 功能的组合。后者旨在通过在客户端 DocumentSession 中缓存包含的文档来减少对数据库的远程调用次数。如果您使用DocumentSession.Load&lt;T&gt;(),这很有效,但如果您使用DocumentSession.Query&lt;T&gt;().Where(x =&gt; x.Id == id) 获取文档,则没有任何区别。如果您熟悉 NHibernate,那么这是您的一级缓存。

    为了让它工作,改变你的代码并改用它:

    List<InstallationSummary> installationSummaries =
        QueryAndCacheEtags(session => session.Advanced.LuceneQuery<InstallationSummary>()
        .Include(x => x.ApplicationServerId)
        .Include(x => x.ApplicationWithOverrideVariableGroup.ApplicationId)
        .Include(x => x.ApplicationWithOverrideVariableGroup.CustomVariableGroupId)
        .OrderByDescending(summary => summary.InstallationStart)
        .Take(numberToRetrieve)).Cast<InstallationSummary>().ToList();
    
    foreach (InstallationSummary summary in installationSummaries)
    {
        summary.ApplicationServer = session.Load<ApplicationServer>(summary.ApplicationServerId);
    
        summary.ApplicationWithOverrideVariableGroup.Application =
            session.Load<Application>(summary.ApplicationWithOverrideVariableGroup.ApplicationId);
    
        if (summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupId != null)
            summary.ApplicationWithOverrideVariableGroup.CustomVariableGroup =
                session.Load<CustomVariableGroup>(summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupId);
    }
    

    【讨论】:

    • 啊啊啊……更干净了。直到今天晚些时候我才能尝试这个。我会让你知道情况如何。谢谢!
    • 哇,有什么不同。请求的数量下降到 1,花费了 40 毫秒而不是 400 毫秒。巨大的改进。再次感谢丹尼尔。
    猜你喜欢
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多