【发布时间】:2021-11-16 19:44:48
【问题描述】:
我正在开发一个遵循领域驱动设计原则的多模块 CMS 应用程序。我正在尝试弄清楚如何实现通用存储库,从而避免大量样板代码。
这个想法是在持久性模块中实现“双向”映射策略(模型到实体,反之亦然)和通用存储库。此外,Domain 模块中的接口将充当 Domain 和 Persistence 之间的合同,因此我可以将其用于以后在其他层中的注入。
我怎样才能使这个接口通用?
具体来说,这里的问题是映射。由于我使用的是“双向”映射策略,因此 Domain 模块不知道特定于 DB 的实体。
有没有办法在层之间映射泛型类型模型?或者在保持层松散耦合的同时使用其他映射策略?
这是一个代码示例,用于阐明我想要实现的目标。 这将是 Generic Repository 的代码示例:
@MappedSuperclass
public abstract class AbstractJpaMappedType {
…
String attribute
}
@Entity
public class ConcreteJpaType extends AbstractJpaMappedType { … }
@NoRepositoryBean
public interface JpaMappedTypeRepository<T extends AbstractJpaMappedType>
extends Repository<T, Long> {
@Query("select t from #{#entityName} t where t.attribute = ?1")
List<T> findAllByAttribute(String attribute);
}
public interface ConcreteRepository
extends JpaMappedTypeRepository<ConcreteType> { … }
此外,我想创建自己的自定义存储库,以便能够将模型映射到实体,反之亦然,因此我的域类中不会有 JPA 特定的注释,从而使其松散耦合。我希望这个自定义存储库实现来自域模块的接口,允许我稍后在服务层中注入它。
public class CustomRepositoryImpl implements CustomRepository {
public final JpaMappedTypeRepository<T> repository;
...
}
我怎样才能使这个类和这个接口通用,以便我能够在模型和实体之间进行映射,因为域层没有关于实体类的信息?
【问题讨论】:
-
我想我们需要看看你写的一些代码。我不清楚你需要什么“接口”才能成为“通用”。
-
另外,你能更清楚你的目标是什么吗?双向映射表明在两个方向上都对域无知,并且实际上没有像操作存储库这样的事情,无论是否通用,而不赋予任何领域知识(至少,您将了解您想要的领域实体取回)。如果你真的认为你需要这种双向解耦,你也需要一个很好的理由去做。所以告诉我们你的理由。
-
否则,显而易见的答案就是传递字符串。字符串是完全不可知的;由接收端解码它们。 有个合法的用例。
-
为什么需要这种“双向”映射?存储库层旨在将模型转换为实体,以便能够使用 ORM 并与数据库进行交互。我看不到这样的情况,您应该在没有存储库层抽象的情况下与该数据库进行交互。只有模型应该有生命周期。如果您需要在其他地方使用实体,它将引入耦合并严重违反 SOLID 原则。这违背了首先完成 DDD 过程的目的。
-
嗨@RobertHarvey,感谢您的评论!我编辑了问题并提供了进一步的说明和示例代码。
标签: java spring-boot spring-data-jpa domain-driven-design ddd-repositories