RavenDB IEnumerable vs List

时间:2012-01-09 02:43:57

标签: linq ienumerable ravendb

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

我不明白的部分是在下面的GetMostRecentByStartTime()方法中使用IEnumerable和List之间的区别。在该方法中,使用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();
    }
}

1 个答案:

答案 0 :(得分:5)

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

在您的情况下,差异的原因是延迟执行和RavenDB的.Include<T>()功能的错误使用的组合。后者旨在通过在客户端DocumentSession中缓存包含的文档来减少对数据库的远程调用次数。如果您使用DocumentSession.Load<T>(),这会很有效,但如果您使用DocumentSession.Query<T>().Where(x => 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);
}