我目前正在做一个项目,我将对类似的非数据库(本讨论的服务层对象)对象和通过 LinqToSql 从数据库检索到的对象进行大量比较。为了便于讨论,假设我有一个服务层 Product 对象,其中包含一个在数据库中表示的字符串字段。但是,在数据库中,还有一个主键 Id 并没有在服务层中表示出来。
因此(就像我经常为单元测试等所做的那样),我覆盖了 Equals(Object)、Equals(Product) 和 GetHashCode 并实现了 IEquatable,并期望我能够编写如下代码:
myContext.Products.Where(p => p.Equals(passedInProduct).SingleOrDefault();
等等。
Equals 覆盖已经过测试并且可以工作。这些对象是可变的,因此通常的警告适用于 GetHashCode 覆盖。但是,出于本示例的目的,除了 LtS 之外,不会修改对象,并且可以将其设为只读。
这是一个简单的测试:
- 在内存中创建一个测试对象并提交到 LtS 上下文。通过提交,测试对象填充了一些自动生成的字段。
- 在内存中创建另一个相同的测试对象(单独参考)
尝试使用第二个对象作为标准从数据库中检索第一个对象。(见上面的代码行)。
// Setup string productDesc = "12A"; Product testProduct1 = _CreateTestProductInDatabase(productDesc); Product testProduct2 = _CreateTestProduct(productDesc); // check setup Product retrievedProduct1 = ProductRepo.Retrieve(testProduct1); //Assert.IsNotNull(retrievedProduct1); // execute - try to retrieve the 'equivalent' product object Product retrievedProduct2 = ProductRepo.Retrieve(testProduct2);
Retrieve 的简化版本(删除的只是参数检查等):
using (var dbContext = new ProductDataContext()) {
Product retrievedProduct = dbContext.Products
.Where(p => p.Equals(product)).SingleOrDefault();
注意:重写的 Equals 方法知道不关心数据库中自动生成的字段,只查看服务层中表示的字符串。
以下是我观察到的结果: 在 testProduct1 上检索成功(毫不奇怪,通过引用相等) 在 testProduct2 上检索失败(null) 在 Retrieve 方法中调用的被覆盖的 Equals 方法在任何一个 Retrieve 调用期间都不会被命中 但是,被覆盖的 Equals 方法被多次调用通过 SubmitChanges 上的上下文(在数据库中创建第一个测试对象时调用)(按预期工作)。
静态地,编译器知道被发射的对象的类型并且能够解析该类型。
所以我的具体问题:
- 我是否试图做一些不明智的事情?似乎是对 Equals 的直接使用。
- 第一个问题的推论:处理 linq to sql 相等性检查的替代建议,同时将比较详细信息保留在对象而不是存储库中
- 为什么我可能观察到在 SubmitChanges 中解决了 Equals 方法,但在 Where 子句中没有解决?
- 我对理解和让我的 Equals 调用工作一样感兴趣。但我也很想学习如何使这种“模式”发挥作用,而不仅仅是理解为什么它在 LtS 和 C# 的竞赛中看起来是一种“反模式”。
请不要建议我直接使用 Where 语句在上下文中进行过滤。显然,我可以删除 Equals 调用并执行此操作。但是,其他一些对象(此处未显示)很大且有点复杂。为了维护和清晰起见,我想知道如何将自己与另一个自己类型的地方进行比较,最好是作为所讨论对象的一部分。
我尝试过的其他一些没有改变行为的事情:
- 重载并使用 == 代替
- 将 lambda 变量转换为类型 p => (Product)p
- 首先获取一个 IQueryable 对象并在 Where 子句中调用 Equals
我尝试过的其他一些不起作用的方法:
- 创建静态 ProductEquals(Product first, Product second) 方法:System.NotSupportedException:不支持对 SQL 的转换。
感谢 StackOverflow 的贡献者!
关于可能的重复:我已经阅读了大约 10 个其他问题。我想要一个指向完全重复的指针,但大多数似乎并没有直接解决 LinqToSql 的奇怪之处。