查询NHibernate中对象存在的最快方法

时间:2009-06-03 12:57:15

标签: nhibernate

我正在寻找检查对象是否存在的最快方法。 该场景非常简单,假设一个目录工具,它读取当前的硬盘驱动器。找到目录后,应该创建目录,或者如果已经存在,则更新目录。

首先,我们只关注创作部分:

    public static DatabaseDirectory Get(DirectoryInfo dI)
    {
        var result = DatabaseController.Session
                      .CreateCriteria(typeof (DatabaseDirectory))
                      .Add(Restrictions.Eq("FullName", dI.FullName))
                      .List<DatabaseDirectory>().FirstOrDefault();

        if (result == null)
        {
            result = new DatabaseDirectory
                         {
                             CreationTime = dI.CreationTime,
                             Existing = dI.Exists,
                             Extension = dI.Extension,
                             FullName = dI.FullName,
                             LastAccessTime = dI.LastAccessTime,
                             LastWriteTime = dI.LastWriteTime,
                             Name = dI.Name
                         };
        }
        return result;
    }

这是可行的方法:

  • 速度
  • 分离关注

我们想到的是:扫描将始终“作为一个整体”执行。这意味着,在扫描驱动器C期间,我知道没有任何新内容被添加到数据库中(来自其他一些进程)。因此,在扫描之前“缓存”所有现有目录可能是一个好主意,并以这种方式查找它们。另一方面,这可能不适合大型数据集,如文件(600.000或更高)......

也许使用“索引列”或类似的东西可以实现一些性能提升,但我对这个主题并不熟悉。如果有人有一些参考,请指出我正确的方向......

谢谢, 克里斯

PS:我正在使用NHibernate,Fluent Interface,Automapping和SQL Express(可以切换到完整的SQL)

注意: 在给定的问题中,路径不是数据库中的ID。 ID是自动增量,我无法更改此要求(其他原因)。所以真正的问题是,检查对象存在的最快方法是什么,ID不知道,只是该对象的属性“

通过选择一个像“以C:Testfiles开头”之类的大组来进行批处理可能是可能的,但问题仍然存在,我怎么知道这个集合有多大。我不能选择“max 1000”并检查这个缓冲的字典,因为我可能“点击搜索到的目录旁边”......我希望这个问题很清楚。最重要的部分是,缓冲真的会影响性能。如果是这样,将整个数据库加载到字典中是否有意义,只包含PATH和ID(即使有1.000.000对象,也可以。)

1 个答案:

答案 0 :(得分:2)

首先,我强烈建议您(任何使用NH的人,真的)阅读Ayende关于differences between Get, Load, and query的文章。

在您的情况下,由于您需要检查是否存在,我会使用.Get(id)而不是查询来选择单个对象。

但是,我想知道您是否可以通过利用您的问题域的一些知识来提高性能。如果您要扫描整个驱动器并检查数据库中是否存在每个目录,则可以通过批量操作获得更好的性能。也许创建一个只包含DatabaseDirectory对象PK的DTO对象,以进一步减少数据传输/处理。类似的东西:

Dictionary<string, DirectoryInfo> directories;
session.CreateQuery("select new DatabaseDirectoryDTO(dd.FullName) from DatabaseDirectory dd where dd.FullName in (:ids)")
    .SetParameterList("ids", directories.Keys)
    .List();

然后只删除那些与返回的ID值匹配的元素,以获取不存在的目录。根据输入集的大小(对于文件,几乎可以肯定),您可能必须将进程分成较小的批次。

就关注点分离而言,只需将操作保持在存储库级别即可。有一个像SyncDirectories这样的方法,它可以处理一个集合(如果你按照上面的说法,可能是Dictionary)来处理更新数据库的过程。这样,你的更高应用程序逻辑就不必担心它是如何工作的,如果你将来找到一种更快的方法就不会受到影响。