NHibernate Linq查询的最佳实践

时间:2013-02-13 18:04:37

标签: linq nhibernate fluent-nhibernate

我有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 profiler。 对于第一个查询,生成的sql包含带有除法表的左外连接。我无法理解为什么它需要加入Division表,因为DivisionId驻留在Doctor表中。这种额外的连接会降低性能吗?

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

1 个答案:

答案 0 :(得分:1)

  

对于第一个查询,生成的sql包含带有除法表的左外连接。我无法理解为什么它需要加入Division表,因为DivisionId驻留在Doctor表中。这种额外的连接会降低性能吗?

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

  

我的第二个问题:如果我想使用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.Id为NULL,它是否足够智能将selectedDivision转换为NULL。试试吧!否则,更安全的方法是写:

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

如果divId恰好为null,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();