我有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中编写此查询?
答案 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。
我通常使用如下模式:
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();