我经常发现自己写这样的查询:
var voyages = db.VoyageRequests.Include("Carrier")
.Where(u => (fromDate.HasValue ? u.date >= fromDate.Value : true) &&
(toDate.HasValue ? u.date <= toDate.Value : true) &&
u.Carrier != null &&
u.status == (int)VoyageStatus.State.InProgress)
.OrderBy(u => u.date);
return voyages;
在where语句中包含条件:
fromDate.HasValue ? u.date >= fromDate.Value : true
我知道另一种方法就是:
var voyages = db.VoyageRequests.Include("Carrier").Where(u => u.Carrier != null &&
u.status == (int)VoyageStatus.State.InProgress);
if (fromDate.HasValue)
{
voyages = voyages.Where(u => u.date >= fromDate.Value);
}
if (toDate.HasValue)
{
voyages = voyages.Where(u => u.date <= toDate.Value);
}
return voyages.OrderBy(u => u.date);
当这两种方法转换为SQL表达式时,是否存在可能影响性能的真正差异?
答案 0 :(得分:2)
第二个查询将创建更简单的SQL,因为fromDate.HasValue
和toDate.HasValue
的评估发生在客户端上。在第一个查询中,三元运算符作为SQL查询的一部分在数据库服务器上进行评估。 fromDate
和toDate
都将作为常量传输到服务器,而在第二个查询中,只有当.HasValue
为true
时才会传输。
我们讨论的是SQL语句长度的几个字节,我不相信三元组的服务器端评估会对查询性能产生任何重大影响。
我会选择你觉得更具可读性的东西。我个人会决定第二个问题。
答案 1 :(得分:1)
如果您想要简单的SQL和更易读的C#,您可以按照Viktor Mitev http://mentormate.com/blog/improving-linq-to-entities-queries/
的建议创建扩展名public static class WhereExtensions
{
// Where extension for filters of any nullable type
public static IQueryable<TSource> Where<Tsource, TFilter>
(
this IQueryable <TSource> source,
Nullable <TFilter> filter,
Expression<Func<TSource, bool>> predicate
) where TFilter : struct
{
if (filter.HasValue)
{
source = source.Where(predicate);
}
return source;
}
// Where extension for string filters
public static IQueryable<TSource> Where<TSource>
(
this IQueryable<TSource> source,
string filter,
Expression<Func<TSource, bool>> predicate
)
{
if (!string.IsNullOrWhiteSpace(filter))
{
source = source.Where(predicate);
}
return source;
}
// Where extension for collection filters
public static IQueryable<TSource> Where<TSource, TFilter>
(
this IQueryable<TSource> source,
IEnumerable<TFilter> filter,
Expression<Func<TSource, bool>> predicate
)
{
if (filter != null && filter.Any())
{
source = source.Where(predicate);
}
return source;
}
然后你的“secound query”将如下所示:
var voyages = db.VoyageRequests.Include("Carrier")
.Where(u => u.Carrier != null && u.status == (int)VoyageStatus.State.InProgress)
.Where(u => u.date >= fromDate)
.Where(u => u.date <= toDate)
.OrderBy(u => u.date);
我不知道它是否更具可读性,或者它是否会让某些开发人员感到困惑,因为直接从代码中读取过滤器的哪个部分正在使用中更加困难。
如果你将扩展函数命名为WhereIfFilterNotNull(或者有意义的东西:-)
,也许它会更具可读性var voyages = db.VoyageRequests.Include("Carrier")
.Where(u => u.Carrier != null && u.status == (int)VoyageStatus.State.InProgress)
.WhereIfFilterNotNull(u => u.date >= fromDate)
.WhereIfFilterNotNull(u => u.date <= toDate)
.OrderBy(u => u.date);