SingleOrDefault()优化是值得的还是过度/有害?

时间:2009-05-06 15:37:09

标签: c# sql linq-to-sql optimization

我正在弄乱LinqToSQL和LINQPad,我注意到SingleOrDefault()没有对生成的SQL进行任何过滤或限制(我几乎期望相当于Take(1))。

所以假设你想保护自己免受大量意外退回的影响,下面的代码片段是否有用或者是个坏主意?


// SingleType is my LinqToSQL generated type 
// Singles is the table that contains many SingleType's
// context is my datacontext
public SingleType getSingle(int id)
{
     var query = from s in context.Singles where s.ID == id select s;
     var result = query.Take(2).SingleOrDefault();
     return result;
}

与通常的方式相反(注意没有.Take(2))


public SingleType getSingle(int id)
{
     var query = from s in Singles where s.ID == id select s;
     var result = query.SingleOrDefault();
     return result;
}

我认为使用Take(2),我仍然可以获得SingleOrDefault()的功能,还有额外的好处,即不必担心意外返回{n}行,但我不确定它是否值得它除非我经常期望用我的查询意外返回{n}行。

那么,这值得吗?有害吗?我有没有看到任何专业人士/骗子?

编辑:

在没有Take(2)

的情况下生成的SQL

SELECT [t0].[blah], (...) 
FROM [dbo].[Single] AS [t0]
WHERE [t0].[ID] = @p0

使用Take(2)生成的SQL


SELECT TOP 2 [t0].[blah], (...) 
FROM [dbo].[Single] AS [t0]
WHERE [t0].[ID] = @p0

另外,当我谈到SingleOrDefault的功能时,我特别希望在返回2个或更多时抛出异常,这就是为什么我在做“Take(2)”。不同之处在于,如果没有.Take(2),它将返回数据库中的{n}行,当它真的只需要返回2时(刚好足以让它抛出)。

4 个答案:

答案 0 :(得分:3)

Single更多是获取查询的单个元素的便捷方法,而不是限制结果数量的方法。通过使用Single,您实际上是在说“我知道这个查询只能包含一个项目,所以只需将它提供给我”,就像在someArray[0]时知道只有一个项目一样元件。 SingleOrDefault添加了返回null的功能,而不是在处理长度为0的序列时抛出异常。对于可能返回的查询,您不应该使用SingleSingleOrDefault超过1个结果:将抛出InvalidOperationException

如果查询中的ID是表的主键或UNIQUE列,则数据库将确保结果集包含1行或不包含{{1} }。clause。

但是,如果您选择非唯一/非键列并想要第一个结果或最后一个结果(请注意,除非您还引入TOP,否则这些结果没有意义),那么您可以使用{ {1}}或OrderBy(两者都有First个对应方)来获取您想要的SQL:

Last

另外,如果您确实在对单个元素进行查询,则可以节省一些输入:

OrDefault

可以成为:

var query = from s in context.Singles 
            where s.Id == id
            orderby s.someOtherColumn
            select s;

var item = query.FirstOrDefault();

答案 1 :(得分:2)

如果序列有多个元素,

SingleOrDefault(以及IEnumerable<T>.SingleOrDefault())都会引发InvalidOperationException。

上面的情况永远不会发生 - 它会引发异常。


编辑:

我的建议取决于您的使用场景。如果您认为有些情况下您将定期从此查询返回多行,则添加.Take(2)行。这将为您提供相同的行为和相同的异常,但消除了从DB返回许多记录的可能性。

但是,您使用SingleOrDefault()表明不应该返回&gt; 1行。如果确实如此,我会把它关掉,只是将其视为例外。在我看来,你通过建议在你添加时获得&gt; 2记录是正常的来减少代码的可读性.Take(2),在这种情况下,我不相信这是真的。我会选择性能。在这种特殊情况下,为了简单起见而将其打破。

答案 2 :(得分:2)

你已经提到了这一点。如果您怀疑查询经常返回大量行,则可能会为您带来性能提升。但如果这是一个例外情况 - SingleOrDefault()清楚地表明 - 这是不值得的。它只会污染你的代码,如果你决定让它进入,你应该记录它。

<强>更新

注意到你正在查询id。我认为它是主键,因此你会得到一行或零行。所以理论上你不应该关心使用Single()First()Take(1)或其他什么。但是我仍然认为使用Single()来明确表明你只想到一行就是好的设计。几周前,一个队列告诉我,他们甚至有一个项目,由于市长数据库故障,一些事情发生了严重错误,主键不再是唯一的。所以比抱歉更安全。

答案 3 :(得分:0)

Allen,ID是Singles表的主键吗?如果是,我不完全理解您的问题,因为您的第二个查询将返回一个记录或null。而SQL将是ID = ### ... 使用Take(2).SingleOrDefault()违背了SingleOrDefault的目的。