【问题标题】:Best practice for NHibernate Linq QueryNHibernate Linq 查询的最佳实践
【发布时间】:2013-02-13 18:04:37
【问题描述】:

我有 3 个 NHibernate 实体

Division
{
  Id (PK),
  Name
}

District
{
  Id (PK),
  Name
}

Doctor
{
  Id (PK),
  Name,
  Division,
  District
}

我想通过 divisiondistrict 获得 doctors 过滤。

我可以通过两种方式编写查询,比如说我有一个用户选择的部门,我想要这个部门下的医生。

第一种方式:

var doctors = doctorRepository
    .FilterBy(x => x.Division.Id == selectedDivision.Id)
    .ToList();

第二种方式:

var doctors = doctorRepository
    .FilterBy(x => x.Division == selectedDivision)
    .ToList();

我的第一个问题是,考虑到性能,哪种方式最好?

我检查了两个查询的 sql profiler。 对于第一个查询,生成的 sql 包含与分区表的左外连接。我不明白为什么它需要加入 Division 表,因为 DivisionId 驻留在 Doctor 表中。这个额外的连接会降低性能吗?

我的第二个问题:如果我想使用 Division 和 District 从医生存储库中查询,并且 Division 和 District 有时可能为空,在这种情况下,我应该如何在 NHibernate Linq 中编写此查询?

【问题讨论】:

    标签: linq nhibernate fluent-nhibernate


    【解决方案1】:

    对于第一个查询,生成的 sql 包含一个与分区表的左外连接。我不明白为什么它需要加入 Division 表,因为 DivisionId 驻留在 Doctor 表中。这个额外的连接会降低性能吗?

    它可能并不严格需要,可能只是这个细节没有被 NHibernate Linq 提供程序优化。除非您的数据库引擎意识到可以对其进行优化(查看 SQL 的执行计划),否则它将影响性能。一般情况下有多少是无法判断的。

    我的第二个问题:如果我想使用 Division 和 District 从医生存储库中查询,并且 Division 和 District 有时可能为空,在这种情况下,我应该如何在 NHibernate Linq 中编写此查询?

    考虑如下查询:

    var doctors = doctorRepository
        .FilterBy(x => x.Division.Id == selectedDivision.Id)
        .ToList();
    

    当由 Linq2NH 执行时,它将被转换为 SQL。如果 x.Division 为 NULL,则不会发生任何坏事,因为在 .NET 中永远不会取消引用该表达式。我不确定 NHibernate 是否会尝试取消对 selectedDivision 的引用(导致 NRE),或者如果 selectedDivision 为 NULL,它是否足够聪明地将 selectedDivision.Id 转换为 NULL。试试看!否则,更安全的方法是写:

    int? divId = selectedDivision != null ? selectedDivision.Id : (int?)null;
    var doctors = doctorRepository
        .FilterBy(x => x.Division.Id == divId)
        .ToList();
    

    如果 divId 恰好为空,NHibernate 足够聪明,可以在 SQL 中生成 IS NULL。

    Null 作为避免过滤的指示

    我通常使用如下模式:

    var queryable = GetMyBaseQueryable<Doctor>();
    
    if (divisionFilter != null)
        queryable = queryable.Where(x => x.Division.Id == divisionFilter.Id)
    
    if (districtIdFilter != null)    // districtIdFilter is some collection
        queryable = queryable.Where(x => districtIdFilter.Contains(x.District.Id))
    
    var result = queryable.ToList();
    

    【讨论】:

    • 顺便说一句,关于我的第二个问题,实际上我想将 null 对象设为可选。实际上,任何 Division 或 District null 都意味着用户不想用它过滤医生。这并不意味着医生的部门或地区 ID 将为空。在这种情况下,如果部门或地区的值为空,我不想在查询中包含此子句。由于我有许多其他参考对象可供医生过滤,这将是最好和最简单的方法?
    • @HabiburRahmanShipon 我添加了一个可选过滤器示例。
    • 可能发生的另一件事是,您的 Division 对象可能会在 selectedDivision 初始化时和查询发生时发生变化,从而混淆 nhibernate 代理,从而导致查询失败。通常最好的做法是通过 Id 引用所有内容,除非您有特殊需要,否则。(此外,在传递整个对象时,传递一个 ID 使用的资源要少得多。这在 Web 应用程序中变得很重要。)跨度>
    猜你喜欢
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    • 2013-10-02
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    相关资源
    最近更新 更多