问题:我在表中有只读数据。它的行没有 id - 只有组合键定义其标识。我希望它在我的应用程序中作为值对象(以 DDD 术语表示(。
研究:但是,如果我放一个@Embeddable
注释而不是@Entity
@Id id
字段,那么javax.persistence.metamodel
看不到它,并在Metamodel metamodel.embeddable(MyClass.class);
上说Not an embeddable
。我可以用 @Entity 类和自动生成 id 来包装它,但这不是我在架构上想要实现的目标。
问:JPA 嵌入是一个值对象吗?嵌入是否可以在没有父实体的情况下存在并表示表?
有许多关于该主题的文章表明这是一个真正的JPA不便:
- http://thepaulrayner.com/persisting-value-objects/
- https://www.baeldung.com/spring-persisting-ddd-aggregates
- https://paucls.wordpress.com/2017/03/04/ddd-building-blocks-value-objects/
- https://medium.com/@benoit.averty/domain-driven-design-storing-value-objects-in-a-spring-application-with-a-relational-database-e7a7b555a0e4
他们中的大多数建议基于规范化关系数据库的解决方案,将标头实体作为一个表,其值对象作为其他单独的表。
由于必须与非规范化的只读表集成,我的挫败感更加严重。该表没有 id 字段,用于存储对象值。没有与标头实体表的绑定。使用 JPA 映射它是一个问题,因为只映射具有 id 的实体。
解决方案是将MyValueObject类与MyEntity类包装在一起,使MyValueObject成为其组合键:
@Data
@Entity
@Table(schema = "my_schema", name = "my_table")
public class MyEntity {
@EmbeddedId MyValueObject valueObject;
}
作为一个轻微的技巧,为了绕过默认空构造函数的 JPA 要求并且不破坏 Value Object 的不变性,我们将其添加为私有并牺牲字段的最终修饰符。隐私和没有资源库符合价值对象的初始 DDD 思想:
// @Value // Can't use, unfortunately.
@Embeddable
@Immutable
@AllArgsConstructor
@Getter
@NoArgsConstructor(staticName = "private") // Makes MyValueObject() private.
public class MyValueObject implements Serializable {
@Column(name = "field_one")
private String myString;
@Column(name = "field_two")
private Double myDouble;
@Transient private Double notNeeded;
}
还有一些龙目岛的@Value
注释来配置值对象。