我正在使用此处描述的策略实现“自动增量”ID: http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
基本上,seqId
字段的值是通过调用实用程序函数来设置的,该函数更新辅助集合上的计数器并返回递增的值。听起来不错。
我的问题在于将此映射与Morphia一起使用。本教程建议执行插入(例如在shell中),如下所示:
db.users.insert(
{
seqId: getNextSequence("userid"),
name: "Sarah C."
}
我基本上希望做一些事情,例如将POJO seqId
字段设置为Morphia在调用save()
时将其转换为上面的插入内容。
我的POJO看起来像这样:
@Entity
public class User {
@Id
private Long id;
// THIS IS THE FIELD I WANT TO AUTO-INCREMENT
private Long seqId;
private String name;
...
}
问题是:如何让Morphia将字段的值设置为函数调用返回的值?
我研究了使用@PrePresist
注释来执行此函数调用并获取值,然后在+ _id字段中设置它。这有几个缺点,比如多次调用MongoDB而不只是一个,还有我的模型对象没有对数据存储区的引用这一事实,我宁愿不要混淆这些问题。
这可能吗?有什么建议吗?
我使用最新的Java驱动程序使用MongoDB 2.6.6。
谢谢!
PS:我知道在大型环境中不建议使用自动增量。无论如何我都需要这个特定场景。
答案 0 :(得分:1)
我将描述对我们有用的解决方案。请注意,这支持类级别的自动增量及其子集 - 因此您可以计算用户或管理员用户(具有管理枚举或其他用户的用户)。
这包含每个自动增量字段的当前值,它基本上是一个引用:
@Entity(noClassnameStored = true)
public class AutoIncrementEntity {
@Id
protected String key;
protected Long value = 1L;
protected AutoIncrementEntity() {
super();
}
/**
* Set the key name — class or class with some other attribute(s).
*/
public AutoIncrementEntity(final String key) {
this.key = key;
}
/**
* Set the key name and initialize the value so it won't start at 1.
*/
public AutoIncrementEntity(final String key, final Long startValue) {
this(key);
value = startValue;
}
public Long getValue() {
return value;
}
}
在您的持久性服务中,您可以使用以下命令自动设置/创建自动增量:
public <E extends BaseEntity> ObjectId persist(E entity) {
// If it's a user and doesn't yet have an ID, set one; start counting from 1000.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getUserId() == null)) {
((UserEntity) entity).setUserId(
generateAutoIncrement(entity.getClass().getName(), 1000L));
}
// Additionally, set an ID within each user group; start counting from 1.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getRoleId() == null)) {
((UserEntity) entity).setRoleId(
generateAutoIncrement(entity.getClass().getName() + "-" + entity.getRole(), 1L));
}
mongoDataStore.save(entity);
return entity.getId();
}
/**
* Return a unique numeric value for the given key.
* The minimum value, set to 1 if nothing specific is required.
*/
protected long generateAutoIncrement(final String key, final long minimumValue){
// Get the given key from the auto increment entity and try to increment it.
final Query<AutoIncrementEntity> query = mongoDataStore.find(
AutoIncrementEntity.class).field("_id").equal(key);
final UpdateOperations<AutoIncrementEntity> update = mongoDataStore
.createUpdateOperations(AutoIncrementEntity.class).inc("value");
AutoIncrementEntity autoIncrement = mongoDataStore.findAndModify(query, update);
// If none is found, we need to create one for the given key.
if (autoIncrement == null) {
autoIncrement = new AutoIncrementEntity(key, minimumValue);
mongoDataStore.save(autoIncrement);
}
return autoIncrement.getValue();
}
最后你的实体:
@Entity(value = "user", noClassnameStored = true)
public class UserEntity extends BaseEntity {
public static enum Role {
ADMIN, USER,
}
private Role role;
@Indexed(unique = true)
private Long userId;
private Long roleId;
// Role setter and getter
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
}
实体中没有具体的内容。所有逻辑都由持久性服务处理。我没有使用@PrePersist
,因为你需要将持久性服务放入实体中,这听起来不是一个好主意。