Spring Data Rest - 如何防止对聚合根的子实体进行PUT/PATCH更新

5
我正在构建一个基于Spring Data REST / Spring HATEOAS的应用程序,并尝试遵循这里(以及其他地方)概述的DDD原则:

BRIDGING THE WORLDS OF DDD & REST - Oliver Gierke

。特别是聚合和通过专用资源进行复杂状态更改的概念。

此外,避免在业务领域中使用HTTP PATCH或PUT进行(复杂的)状态转换,因为您会错过有关触发此更新的实际业务领域事件的大量信息。例如,更改客户的邮寄地址是对新的“ChangeOfAddress”资源的POST,而不是对具有不同邮寄地址字段值的“Customer”资源的PATCH或PUT。

我正在努力找到一种强制执行此规则的方法,同时允许对聚合根进行外观上的更改。
使用以下简化示例:
@Entity
public class Customer
{
   private @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id;

   private String name;

   private String comment;

   @Access(AccessType.PROPERTY)
   @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
   private Set<Address> addresses = new HashSet<>();

   ... getters and setters

    public void addAddress(Address address)
    {
        addresses.add(address);
        ... custom code to raise events etc
    }
}

public interface Customer extends CrudRepository<Customer, Long>
{
}

什么是允许进行视觉变化(例如更新注释)但阻止直接更新子集合的最佳/正确方法?
唯一我能想到的方法是,如果有修改子集合的尝试,则使setter抛出异常。

2
恭喜,您刚刚撞上了SDR中的一个深达一米的坑洼。 - chrylis -cautiouslyoptimistic-
2
您可以在映射时防止从请求中读取数据。如果您正在使用Jackson,请使用@JsonProperty(access = JsonProperty.Access.READ_ONLY)标记您的子集合。因此,该字段仅允许提供服务,但不允许更新。 - Bogdan Oros
@BogdanOros 谢谢,这个很好用。如果你把它作为答案放上来,我会接受它的。 - Adam Jones
@chrylis 我认为这不一定是SDR的缺点,如果我使用Spring mvc/hateoas并手写控制器,我仍然会遇到同样的问题。问题更多地源于尝试实现聚合模式。 - Adam Jones
1个回答

1
@Entity
public class Customer
{
   private @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id;

   private String name;

   private String comment;

   @JsonProperty(access = JsonProperty.Access.READ_ONLY)
   @Access(AccessType.PROPERTY)
   @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
   private Set<Address> addresses = new HashSet<>();
}

1
再次感谢@Bogdan Oros。如果至少有一个Spring Data Rest示例涵盖了这一点,那将是很好的。在应用聚合模式时,这似乎是一个重要考虑因素。 - Adam Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接