Как заставить Morphia установить значение поля как значение, возвращаемое вызовом функции?

1

Я реализую идентификатор "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: Я знаю, что автоматическое увеличение не рекомендуется в больших средах. Мне это нужно в любом случае для этого конкретного сценария.

Теги:
auto-increment
morphia

1 ответ

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 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, потому что тогда вам нужно будет поместить службу сущности в объект, что не похоже на хорошую идею.

  • 0
    Спасибо! Я предполагаю, что в настоящее время нет способа выполнить то, что я хотел, без первого обхода сервера, но это хороший обходной путь к проблеме «хранилище данных в объектах сущностей».

Ещё вопросы

Сообщество Overcoder
Наверх
Меню