Linq to SQL - 什么更好?

5
db.Albums.FirstOrDefault(x => x.OrderId == orderId)

或者

db.Albums.FirstOrDefault(x => x.OrderId.Equals(orderId))
4个回答

9
我将试图说服您:
  • 您提出的两种方法具有相同的性能。
  • 至少有两个与性能无关的原因,您应该更喜欢使用==
  • 还有另一种单独的改进方法可以减少错误的可能性。

要查看性能是否相同,请查看每种情况下生成的SQL。此测试程序向您展示了如何查看生成的SQL:

int orderId = 4;
TextWriter textWriter = new StringWriter();
using (var dc = new DataClasses1DataContext())
{
    dc.Log = textWriter;
    Order o1 = dc.Orders.FirstOrDefault(x => x.OrderId == orderId);
    Order o2 = dc.Orders.FirstOrDefault(x => x.OrderId.Equals(orderId));
}
string log = textWriter.ToString();

每种情况下发送的SQL语句都是相同的,您可以通过检查日志来查看:
SELECT TOP (1) [t0].[OrderId], [t0].[CustomerID], [t0].[Date], [t0].[Description]
FROM [dbo].[Order] AS [t0]
WHERE [t0].[OrderId] = @p0

SELECT TOP (1) [t0].[OrderId], [t0].[CustomerID], [t0].[Date], [t0].[Description]
FROM [dbo].[Order] AS [t0]
WHERE [t0].[OrderId] = @p0

关于使用==还是Equals,首先我建议使用==来提高可读性。这是在C#中比较两个整数的惯用方式。

其次,如果你给出不同(不兼容)类型的对象,使用==会在编译时产生错误。我假设在你的情况下,order的类型为int,但让我们假设其他人编写了这段代码,并意外地将order变量的类型设置为Order而不是int。现在让我们比较一下每种情况下会发生什么:

Order order = new Order { OrderId = 4 };

x.OrderId.Equals(order)  // This compiles, but you get an exception at runtime:
                         // Could not format node 'Value' for execution as SQL.

x.OrderId == order       // Compile error: Operator '==' cannot be applied to
                         // operands of type 'int' and 'Order'

在编译时出现错误总比在运行时出现错误要好,因此在这种情况下最好使用 ==

最后,如果您只期望一个结果,则应该优先使用 SingleOrDefault 而不是 FirstOrDefault,因为前者会在找到两个匹配对象时抛出异常而不是仅返回第一个。这个额外的检查会花费一点性能,但是可以让您更早地捕获错误。如果性能对您来说是关键问题,那么您应该考虑一次从数据库中获取多个对象,而不是逐个获取一个对象,而不是删除这些安全检查。

因此,总结起来,我建议您使用以下内容:

Album album = db.Albums.SingleOrDefault(x => x.OrderId == orderId);

我是指订单具有整数类型。 - Sasha

7

从性能角度来看,它们都是等效的。我更喜欢使用==而不是.Equals(),因为后者更易读,但L2S的美妙之处在于你可以根据拥有的对象类型选择其中任何一个。

(我假设你的第二个语句是关于orderId而不是order对象)


我已经好几年没写C#了,但这不是一个自动装箱的问题吗,而不是L2S的问题吗?或者==取决于手头的实例吗? - Dan Rosenstark
@yar:没有进行装箱操作,而是对表达式树进行访问和转换成SQL查询。 - Aaronaught
@Aaronaught,是的,我现在明白了,但真希望我当时能仔细看一下代码 :) 同时,我还得学习一下表达式树,因为我原本以为“param”会在FirstOrDefault获取它之前被评估。显然这是不正确的。 - Dan Rosenstark

1
在大多数情况下,您应该获得相同的结果。然而,还是有差别的。
使用操作符 Equals 来确定两个对象实例是否相同。 操作符 == 确定两个对象是否具有相同的值。
在这种情况下,我使用了 == 操作符,因此更易读。

3
+1 很好的观点。如果数据库中的 OrderId 为空,那么这个 L2S 是否会转换成 x.Order == null?如果是的话,.Equals 调用将失败,因为左侧没有有效的对象。 - Binary Worrier
Int32、Guid和所有其他值类型/基元类型都有重载的Equals方法,可以接受相同类型的参数。唯一会产生不同结果的情况是,如果orderId参数实际上与Order.OrderId属性的类型不同。 - Aaronaught
这是错误的:System.Object上的Equals方法被标记为虚拟的,可以被重写。它应该与==做相同的事情。 - Arjan Einbu
@Arjan Einbu 你的说法部分正确。在使用==运算符时,String类内部使用静态Equals方法。这个方法首先使用==运算符检查字符串是否为同一对象。这相当于使用Object.ReferenceEquals方法。 如果两个字符串都不为null,则静态Equals方法调用左侧字符串的实例方法Equals,并将右侧字符串作为参数传递以执行字符串比较。 - Tim

0

差不多一样。如果你只想检查值,那么应该使用

==

如果您想检查值以及它们是否为相同实例,请使用

Equals

但在这两种情况下,结果时间几乎相同。


2
“Equals”并不意味着引用相等。当参数都是引用类型时,它可能会执行引用检查,但在这方面它与“==”基本相同。如果您想要引用相等,则使用“object.ReferenceEquals”方法。 - Aaronaught

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接