Я реализую идентификатор "auto-increment", используя описанную здесь стратегию: http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
В основном значение поля seqId
задается вызовом функции утилиты, которая обновляет счетчик в вспомогательной коллекции и возвращает добавочное значение. Звучит здорово.
Моя проблема заключается в сопоставлении этого с Морфией. Учебное пособие предлагает выполнить вставку (например, в оболочке) следующим образом:
db.users.insert(
{
seqId: getNextSequence("userid"),
name: "Sarah C."
}
Я в основном seqId
сделать что-то вроде установки поля 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, а не только одного, а также того факта, что мои объекты модели не имеют ссылки на хранилище данных, и я бы предпочел не смешивать проблемы.
Это возможно? Какие-либо предложения?
Я нахожусь на MongoDB 2.6.6, используя новейшие Java-драйверы.
Благодарю!
PS: Я знаю, что автоматическое увеличение не рекомендуется в больших средах. Мне это нужно в любом случае для этого конкретного сценария.
Я опишу решение, которое работает для нас достаточно хорошо. Обратите внимание, что это поддерживает автоматические приращения уровня класса и его подмножества, поэтому вы можете подсчитывать пользователей или администраторов (пользователь с перечислением администратора или что-то еще).
Это содержит текущее значение для каждого поля автоматического приращения, в основном это ссылка:
@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 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
, потому что тогда вам нужно будет поместить службу сущности в объект, что не похоже на хорошую идею.