【问题标题】:linq2sql, repository pattern - how to query data from two or more tables?linq2sql,存储库模式 - 如何从两个或多个表中查询数据?
【发布时间】:2011-05-17 17:47:15
【问题描述】:

我使用 Repository 模式(和 linq2sql 作为数据访问),并且有例如 ProductsRep 和 CustomersRep。

在非常简单的场景中,db 有两个表 - Produsts(ProductID、CustomerID、ProductName、Date)和 Customer(CustomerID、FirstName、LastName)。

每个存储库都提供创建、更新、删除和获取特定模型对象的方法,并且可能是一些过滤器。

但如果我想通过产品名称查询购买特定产品的所有客户,我必须使用 ProductsRep 获取该产品的 ProductID,然后使用 CustomersRep 获取所有购买具有此 id 产品的客户。

我说的对吗?这其实是l2s必须生成的两个sql请求,难道只能做一个请求吗?

而且,一般来说,如果我们想使用具有关系和存储库模式的多个表来查询数据,如何通过将查询量降至最低来做到这一点?

谢谢。

【问题讨论】:

  • 如果你能画出你的表格,你的问题会更容易理解。名称和列。请在文本中使用一些换行符。
  • 您不应该按表对存储库进行分组(如果您应该对它们进行分组的话),而是按使用情况。

标签: performance linq-to-sql architecture repository-pattern


【解决方案1】:
var customers = from cust in CustomersRep
                join prod in ProductsRep on prod.CustomerID equals cust.CustomerID
                where prod.ProductName == yourInput
                select cust;

您可以编写一个查询,类似于在 SQL 中(基本上)。上面的yourInput 是保存您感兴趣的产品名称的变量。

只要 ProductsRep 和 CustomersRep 在同一个数据库中,这应该会给您一个数据库查询请求。

【讨论】:

  • 如果在我们的 CustomersRep 和 ProductsRep 中有一个 GetAll() 方法返回所有实体的 IQueryable,并且我们使用您的方法,我们会立即得到异常“查询包含对定义的项目的引用不同的数据上下文。”,因为存储库被引用到不同的数据上下文
  • 在两种不同的环境中使用您的表有什么好处?
  • 我尝试实现存储库模式,每个存储库都创建自己的数据上下文,现在我明白这对于某些场景来说不是一个好主意...
【解决方案2】:

想想你的陈述:

但是如果我想查询所有客户 按产品购买特定产品 名字,我必须得到这个的ProductID 产品使用 ProductsRep 然后得到 所有购买产品的客户 此 id 使用 CustomersRep。

这闻起来很麻烦。 创建一个存储库以促进您域的隔离区域中的行为,而不是针对每个业务实体。

DDD/Repository 的一个常见错误是考虑数据。别。想想行为。

您有一个 Products 实体,它指的是 Customer。这意味着没有客户,产品就无法存在。正确的?因此,客户是您的聚合根 - 它控制您的域模型这一部分的行为。

您对上述答案的评论证实 - 您正在跨多个存储库工作。您有两个选择 - 1) 工作单元,2) 修复您的存储库设计。

您只需要 1 个存储库 - 我们称之为 CustomerProductRepository

然后进行上述查询:

var customersWhoBuyHats = customerProductRepository
                             .Products
                             .Include("Customer")
                             .Where(x => x.ProductName == "Hat")
                             .Select(x => x.Customer)
                             .ToList();

结果是 List<Customer>,您只需调用一次数据库即可。

HTH。

【讨论】:

  • 我的错 - 忘了你在使用 L2SQL。 Include 是英孚。 L2SQL 中的等价物是DataLoadOptions。不过,您会得到我的答案的要点(我希望)。还有一点 - 带有 IQueryable 的存储库确实不适合 L2SQL。如果你想获得这个 DDD'ey,那么你应该考虑转移到实体框架。
  • 我找到了另外两个解决方案,它们可能相当不错。 1) 我们为所有存储库使用一个 DataContext 实例,因此我们可以毫无例外地使用 IQueryable 进行操作。 2)为了从多个表中检索数据,我们使用数据库中的视图,使用 L2S 映射到类,存储库仅用于 CRUD。这种方法怎么样?为什么带有 IQueryable 的存储库真的不适合 L2SQL?
  • 您应该使用方法 1。我不知道您为什么需要多个数据上下文,除非您在不同的机器上拥有数据库。将 DataContext 传递给 Repository 的 ctor,这样所有的存储库都可以使用同一个 DC。
  • 关于我关于使用 L2SQL 的 Repository/IQueryable 的声明 - L2SQL 不支持表的 POCO 映射。这意味着您的 IQueryable/Repository 正在将实际的表实体返回到您的较低层。除非您手动将它们投影到 POCO 中,否则您如何保存该实体?您需要从左到右的属性复制来将 POCO 转换为 L2SQL 实体。无论哪种方式,您的存储库都会变得过于复杂,无法达到其目的。 EF 支持开箱即用的 POCO,使得抽象非常容易。
  • 现在我使用您描述的方法 - 我的存储库返回 POCO 对象,该对象转换为 L2SQL 实体,反之亦然,它相当复杂,是的。我坚信我迟早应该开始学习 EF。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 2013-12-01
  • 2017-12-05
  • 2018-09-08
  • 2015-07-12
  • 1970-01-01
相关资源
最近更新 更多