Обновляемый атрибут JPA и JPQL - PullRequest
0 голосов
/ 16 октября 2011

Я сделал пару наблюдений в своем тесте, и мне трудно их понять. Мои тесты выполняют некоторые базовые операции обновления (или слияния) для сущности, один из атрибутов которой установлен как updatable = false.


@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(generator = "some-generator")
    @Column(name = "EMP_ID", nullable = false)
    private Long id;

    @Column(name = "EMP_NAME", updatable = false)
    private String name;

    @Version
    @Column(name = "OBJECT_VERSION")
    private int version;

    public Employee() {
    }

    public Employee(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


Примечание. Я использую Hibernate в качестве поставщика сохраняемости.

Мои наблюдения и сомнения

  1. Свойство name указанного выше объекта Employee имеет Updatable = "false". Если я загружаю и устанавливаю свойство name сущности сотрудника, а затем вызываю entityManager.merge (employee), слияние не выполняет никакого запроса на обновление, которое является ожидаемым поведением, но оно также не выдает никакого исключения. Можно ли настроить JPA таким образом, чтобы генерировалось исключение времени выполнения?

  2. Вместо вызова entityManager.merge (employee), если свойство name обновляется с использованием запроса JPQL, запрос выполняется успешно, а свойство name обновляется. В чем техническая причина, по которой поведение запроса JPQL отличается от обновления объекта JPA и почему?

  3. Если обновление выполняется с использованием запроса JPQL, номер версии не увеличивается, несмотря на аннотацию @Version. Я понимаю, что такое поведение может быть достигнуто путем добавления ключевого слова "versioned" в запросе на обновление, но я хотел бы понять технические причины, по которым свойство version не будет обновляться при выполнении запроса JPQL.

Поскольку JPQL является объектно-ориентированным языком запросов (как и HQL), я думаю, что не должно быть технических проблем с реализацией для пунктов 2 и 3. Было бы здорово услышать некоторые комментарии экспертов по этому поводу. Спасибо.

1 Ответ

2 голосов
/ 16 октября 2011
  1. Ну, в спецификациях просто говорится, что когда столбец является обновляемым = "false", он должен игнорироваться сгенерированным SQL.Ничего не говорит о создании исключения.Однако вы можете реализовать это с помощью слушателей.Просто объявите метод в вашем bean-компоненте, например "checkModif", добавьте к нему @PreUpdate и добавьте исключение из него, если поле изменено (обратите внимание, однако, что это эффективно отменит операцию, и ничего не будет обновлено)

  2. Это скорее ошибка Hibernate.Спецификации JPA2 просто говорят, что когда поле помечено @Column(name = "EMP_NAME", updatable = false), соответствующий столбец должен игнорироваться SQL, генерируемым поставщиком.Ничего не говорится о конкретном случае, когда этот SQL исходит из JPQL.В реализации JPA2 в Hibernate есть много маленьких «сбоев» (например, невозможность поиска с помощью ключа в сопоставлении карты

  3. AFAIK, номер версии следует увеличивать только при использовании оптимистическогоблокировка, поэтому при использовании JPQL вы должны указать, действительно ли вы хотите увеличить его или нет.

Пример:

Сценарий 1: вы хотите получить право сотрудника, а затемизмените его. Если вы действительно вносите некоторые изменения в сущность Employee, вы хотите, чтобы эти изменения сохранялись только в том случае, если никто другой не внес некоторые изменения в тот же объект во время между его первым чтением и временем фиксации вашей модификации.случается, вы читаете свою сущность так:

Query query = entityManager.createQuery("SELECT e FROM EMPLOYEE e where e.id=3");
query.setLockMode(LockModeType.OPTIMISTIC);
Employee e = query.getSingleResult();

Таким образом, если какой-то другой пользователь использует тот же код выше для чтения той же сущности во время ее изменения, и эти новые парни быстрее васи совершает модификацию быстрее, чем вы, тогда, если вы сами что-то измените и попытаетесьдля фиксации вы получите OptimisticLockException, и вы не получите коммиты ваших модификаций, таким образом, не переопределяя (неизвестные вам на данный момент) модификации, которые сделал другой парень.

Сценарий 2. Вы хотите быть увереннымчитать сущность, и когда вы сохраняете ее, даже если вы ничего не изменили в ней, вы хотите сохранить ее (с теми же значениями), только если никто не изменил что-либо еще в то же время.Для этого вы делаете

Query query = entityManager.createQuery("SELECT e FROM EMPLOYEE e where e.id=3");
query.setLockMode(LockModeType.OPTIMISTIC_FORCE_INCREMENT);
//etc etc...

В обоих сценариях сущность Employee должна иметь поле с версионностью, чтобы это работало:

@Version
protected int version;

public int getVersion() {
    return version;
}

public void setVersion(int version) {
    this.version = version;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...