0

我有 3 个 NHibernate 实体

Division
{
  Id (PK),
  Name
}

District
{
  Id (PK),
  Name
}

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

我想让医生按部门地区过滤。

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

第一种方式:

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

第二种方式:

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

我的第一个问题是,考虑性能的最佳方式是什么?

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

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

4

1 回答 1

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),或者如果为 NULL,它是否足够聪明以转换selectedDivision.IdselectedDivisionNULL。尝试一下!否则,更安全的方法是编写:

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

如果 divId 恰好为空,NHibernate 足够聪明,可以在 SQL 中生成 IS 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();
于 2013-02-13T18:30:28.000 回答