我最近从学习域驱动设计(DDD)中学到的一个想法是,使用具有有意义名称的域对象包装数据类型(如字符串和基元)会很不错。例如,如果我有一个com.example.Account
域对象,我将要存储在MongoDB中,它可能有一个类型为java.lang.String
的id字段。相反,让id字段为com.example.AccountId
类型可能会很好,因为它读取得相当好,并且有助于作为代码的一种自我文档。它也可以是一个编译时防御,以防止意外传递另一种id也恰好是一个字符串......
我在使用Spring Data MongoDB
尝试实现此问题时遇到了一些麻烦我从一个Account对象开始,该对象只有一个名为" id"的字段。类型为java.lang.String
。我的Spring Data Repository定义如下:
public interface AccountRepository extends PagingAndSortingRepository<Account, String> {}
这很好用,我可以保存将自动生成MongoDB标识符的帐户实例,例如:5436fd21300415af8c9201e0
。
首先,我按如下方式定义一个对象:
public class AccountId implements Serializable {
private final String id;
public AccountId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
然后我将帐户中id字段的类型更改为AccountId
,最后将存储库定义更改为:
public interface AccountRepository extends PagingAndSortingRepository<Account, AccountId> {}
当我尝试保存帐户的实例时,我得到一个例外:
org.springframework.dao.InvalidDataAccessApiUsageException: Cannot autogenerate id of type com.example.AccountId for entity of type com.example.Account!
at org.springframework.data.mongodb.core.MongoTemplate.assertUpdateableIdIfNotSet(MongoTemplate.java:1149)
at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:878)
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:833)
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
我可以做些什么(如果有的话)来实现这种行为?