我正在努力了解如何最好地查询存储库。
现在让我通过循环的三个因素是:
第1点
关于问题一:
我有许多方法的存储库,它们返回实体和标量值的组合。这似乎导致"方法爆炸"。我应该总是返回一个Entity对象吗?我该如何查询只需要一列的对象?
第2点 在运行查询时,我是否应该包括表中的每一列,即使我只需要一列或两列?如果我为此创建特定查询,则会导致存储库中的更多方法
第3点 我该如何为查询提供条件?我读到了有关规范的内容,但我的理解是您遍历返回的记录并过滤掉传入新集合的记录。这并不是一个明智的表现。现在我只是在Repo中创建一个新方法,比如getNameById(),它封装了条件。
请注意,我没有使用ORM,我的存储库中只有原始的SQL 。
更新
第1点: 根据答案和更多的研究,这将是一个很好的实施?
现在我有一个大型存储库,它返回标量和实体类型对象的混合(所有相同的实体)。我想如果我只使用GetUser(userId)方法并忘记编写只返回单列值的方法,我可以大大减少这一点。
例如,如果我需要返回一个用户名,我可以调用GetUser(userId)方法来保护User对象,然后在服务层中将其过滤为用户名。
另一种方法是使用某种我可以传递到Repository的QueryBuilder类,可以解析它以生成正确的sql。
第2点
回顾这一点非常类似于第一点,我目前的解决方案是只抓取所有表字段。它是性能和可维护性之间的权衡。
第3点
我需要提供某种where子句。我不确定这是否有意义通过规范或只是一个SQL字符串。我目前的解决方案是为这些类型创建新的方法,但我想要一些更通用的存储库
总的来说,仍然在研究这个...我喜欢听到更多关于这方面的意见,或者链接到书籍或参考文献,这些都将这一切联系在一起。
答案 0 :(得分:3)
我有许多方法的存储库,它们返回实体和标量值的组合。这似乎导致“方法爆炸”。我应该总是返回一个Entity对象吗?我该如何查询只需要一列的对象?
您可以对抗存储库方法爆炸,类似于您对抗其他SRP违规的方式。您可以为同一实体创建另一个存储库。请参阅此answer以查找类似的问题。
运行查询时,即使我只需要一列或两列,我是否应该在表中包含每一列?如果我为此创建特定查询,则会导致存储库中的更多方法
这不是DDD问题。 域驱动设计不处理“行和列”。加载的数据总是存在一些冗余,以“加湿”域对象,但您必须衡量这是否真的会影响您的性能。如果这确实是性能瓶颈而不是可能是域模型不正确的症状。
我应该如何为查询提供条件?我读到了有关规范的内容,但我的理解是您遍历返回的记录并过滤掉传入新集合的记录。这似乎不是一个明智的表现。现在我只是在Repo中创建一个新方法,比如getNameById(),它封装了条件。
这又是一个数据访问问题。 DDD中没有任何内容表明您的存储库无法将Specification转换为SQL查询。无论您是这样做还是迭代内存中的记录(只要存储库使用者只看到规范和存储库并且不知道实际的实现),由您决定。
关于'原始SQL与DDD中的ORM',您可能会发现此answer很有趣。
答案 1 :(得分:2)
我同意德米特里所说的一切,但也许你认为你应该读一读CQRS。
我开始使用DDD时曾经问过类似的问题(关于'方法爆炸',而不是你的SQL问题),这导致我CQRS。就个人而言,如果没有它,我真的不知道DDD是如何实用的,它在查询数据时会回答很多这类问题。使用它的原则我建议的是:
这可以保持你的正确领域和存储库干净,同时提供创建提供高性能查询的瘦数据访问层的方法。
关于规范模式:您可以在代表条件的规范上提供公共属性,而不是将其转换为代码中的SQL查询。然后可以将这些值添加到SQL的where子句中,或作为参数发送到SPROC。
答案 2 :(得分:1)
首先,您还没有真正解释您使用所有这些查询的内容。有可能是用户界面需求。如果是这样,则无需跳过所有这些环节(service-> repository-> domain-> dto-> client),只需要尽可能直接查询数据库。你知道什么,不管你是否可以查询标量或只是你需要的列的问题。只需使用普通的SQL并返回您需要的内容。不要创建导致摩擦的抽象。
答案 3 :(得分:1)
Chobo,
我们需要记住有关Repository [Fowler PoEAA] [Evans DDD]模式的两件事:
另外两种类型可能有助于您的存储库:查询对象[Fowler PoEAA]和数据映射器[Fowler PoEAA]模式。使用面向对象的方法查询对象模式聚合标准,并知道如何将它们转换为SQL语句。数据映射器模式知道应用程序中的对象状态和数据库中的表列。
您可以使用延迟加载模式[Fowler PoEAA]来缓解内存中大对象的问题。
成功!