DDD:领域与持久化模型分离场景下额外属性传递方案咨询
解决DDD中领域模型与多持久化模型的额外属性传递问题
我来分享几个在DDD实践中常用的解决方案,帮你处理这类非领域属性(比如modifiedOn、modifiedBy)的传递问题:
1. 用映射层统一处理属性赋值
这是最直观也最常用的方案——专门做一个映射层(手动写映射类或者用MapStruct这类工具),在领域模型转持久化模型的过程中,把额外属性的值注入进去。
比如手动实现映射逻辑的伪代码:
public class EntityMapper { // 领域模型转第一个持久化模型 public PersistenceEntity1 toPersistence1(DomainEntity domain, String modifiedBy, LocalDateTime modifiedOn) { PersistenceEntity1 entity1 = new PersistenceEntity1(); entity1.setDomainProperty1(domain.getProperty1()); // 赋值应用层属性 entity1.setAppProperty1(modifiedBy); entity1.setModifiedOn(modifiedOn); entity1.setModifiedBy(modifiedBy); return entity1; } // 领域模型转第二个持久化模型 public PersistenceEntity2 toPersistence2(DomainEntity domain, String modifiedBy, LocalDateTime modifiedOn) { PersistenceEntity2 entity2 = new PersistenceEntity2(); entity2.setDomainProperty2(domain.getProperty2()); entity2.setAppProperty2(modifiedBy); entity2.setModifiedOn(modifiedOn); entity2.setModifiedBy(modifiedBy); return entity2; } }
如果用MapStruct这类工具,还可以通过@Context注解传递包含这些属性的上下文对象,让工具自动生成带属性赋值的映射代码,减少手动编写的工作量。
2. 借助应用服务传递上下文数据
应用服务作为领域层和基础设施层的中间层,天然适合处理这类非领域的应用属性。你可以在应用服务里:
- 从上下文(比如ThreadLocal、安全上下文)获取当前操作的用户信息
- 生成当前时间戳
- 然后在调用映射或持久化操作时,把这些数据传递进去
这种方式能保证领域模型的纯净性,不会让非领域属性污染领域层的代码。
3. 用ORM拦截器/切面自动填充
大部分ORM框架(比如Hibernate、MyBatis)都支持拦截器或切面机制,可以在持久化操作(保存/更新)之前自动填充通用的审计属性:
比如用Hibernate的实体监听器实现自动填充:
// 定义一个通用的审计接口 public interface Auditable { void setModifiedBy(String user); void setModifiedOn(LocalDateTime time); } // 实现监听器 public class AuditListener { @PrePersist @PreUpdate public void fillAuditFields(Object entity) { if (entity instanceof Auditable) { Auditable auditable = (Auditable) entity; // 从安全上下文获取当前用户 String currentUser = SecurityContextHolder.getContext().getAuthentication().getName(); auditable.setModifiedBy(currentUser); auditable.setModifiedOn(LocalDateTime.now()); } } }
然后让PersistenceEntity1和PersistenceEntity2实现Auditable接口,配置好监听器后,ORM框架就会在持久化时自动帮你填充这些属性,不用在业务代码里重复写赋值逻辑。
4. 封装上下文对象传递
如果这类额外属性比较多,建议封装一个AuditContext对象,把modifiedBy、modifiedOn、createdBy等属性都放在里面:
public class AuditContext { private String modifiedBy; private LocalDateTime modifiedOn; // 其他属性和getter/setter }
然后在应用服务里创建并填充这个上下文对象,作为参数传给映射层,映射层从上下文里取出对应的值赋值给持久化实体,这样能避免方法参数过多,代码更规整。
内容的提问来源于stack exchange,提问作者msmani
相关产品推荐
相关产品推荐

