我正在弄乱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}行。
那么,这值得吗?有害吗?我有没有看到任何专业人士/骗子?
编辑:
SELECT [t0].[blah], (...)
FROM [dbo].[Single] AS [t0]
WHERE [t0].[ID] = @p0
SELECT TOP 2 [t0].[blah], (...)
FROM [dbo].[Single] AS [t0]
WHERE [t0].[ID] = @p0
另外,当我谈到SingleOrDefault的功能时,我特别希望在返回2个或更多时抛出异常,这就是为什么我在做“Take(2)”。不同之处在于,如果没有.Take(2),它将返回数据库中的{n}行,当它真的只需要返回2时(刚好足以让它抛出)。
答案 0 :(得分:3)
Single
更多是获取查询的单个元素的便捷方法,而不是限制结果数量的方法。通过使用Single
,您实际上是在说“我知道这个查询只能包含一个项目,所以只需将它提供给我”,就像在someArray[0]
时知道只有一个项目一样元件。 SingleOrDefault
添加了返回null
的功能,而不是在处理长度为0的序列时抛出异常。对于可能返回的查询,您不应该使用Single
或SingleOrDefault
超过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的目的。