2014-11-19 2 views
0

JPA 2.0 (Спящий 4.2.4.Final/Spring 3.2.8.Release)/Mysql 5.6JPA Полученное значение столбца на основе столбца идентичности

Для управляемого объекта E ж/автоматически сгенерированный первичный ключ, например,

... 
@Id 
@GeneratedValue 
private int id; 

@Column 
private String foo; 

@Version 
@Column(name="mod_date") 
private Timetamp modDate; 
... 

foo должен быть равен: {id}: по старым причинам. Например. если идентификатор был 204, Foo будет «: 204:» Для этого ж/в транзакции это то, что работает

em.persist(e); 
em.detach(e); 
e = em.find(e.getId()); 
e.setFoo(":" + e.getId() + ":"); 
... 

Есть ли лучший способ вычисления производной столбца, где значение зависит от генерируемый идентификатор? Без вышеуказанного взлома, то есть прямое обновление столбца после сохранения результатов в org.hibernate.StaleObjectException. Я вижу, что это происходит в модульных тестах (на самом деле я могу пройти через единичный тестовый код и воспроизвести исключение, исключающее проблему с несколькими потоками, обычно связанную с/StaleObjectException

+0

Установка определения столбца mod_date как timestamp (3) в mysql избавилась от исключения StaleObjectException, которое привело меня к неправильному пути. Теперь используйте @PostPersist, и он отлично работает. Thx Alan Hay. – user5842

ответ

0

Вы можете использовать прослушиватель событий JPA PostPersist, чтобы справиться с этим.

@Id 
@GeneratedValue 
private int id; 

@Column 
private String foo; 

@PostPersist 
public void onSave(){ 
    foo = ":" + id + ":"; 
} 

Из спецификации JPA 2:

Метода обратного вызова PostPersist и PostRemove вызывается для объекта после того, как лиц, был сделан постоянным или удален. Эти обратные вызовы также будут вызываться для всех объектов, к которым каскадируются эти операции . Методы PostPersist и PostRemove будут вызывать после операций вставки и удаления базы данных соответственно. Эти операции с базой данных могут возникать непосредственно после того, как были вызваны операции сохранения, слияния или удаления или они могут быть вызваны непосредственно после выполнения операции сброса (которая может быть на в конце транзакции). Значения генерируемых первичных ключей: , доступные в методе PostPersist.

+0

Это именно то, что я пробовал, но, к сожалению, это было неудачно из-за исключения StaleObjectException. (Mea culpa - должен был упомянуть об этом в исходном сообщении). Оказалось, что это проблема с тем, как временные метки обрабатываются в MySQL 5.5 vs 5.6. См. Пересмотренный пост. Вернемся к тому, что вы предложили – user5842

0

Лучшее решение - просто вычислить значение столбца на загрузка, использование @Formula:

@Formula(value="':'||id||':'") 
private String foo; 
+0

Мы пытаемся придерживаться только синтаксиса JPA. Поверьте, это конкретная реализация Hibernate. – user5842

+0

Да, это Hibernate. Но в то же время это очень эффективный способ решения вашей проблемы. –

+0

Не согласен с вами вообще в отношении эффективности или ограниченности решения. Просто стараюсь строго придерживаться стандарта JPA и не использовать расширения для конкретных поставщиков. Его все еще одна дискуссия о том, что мы когда-нибудь перейдем от Hibernate, чтобы сказать TopLink :) – user5842

0

вы можете создать перехватчик для этого требования см ниже пример:

Допустим, у вас есть объект, называемый Student со свойствами id (действует как идентификатор) и foo.

@Entity 
@Table(name = "test_student") 
public class Student { 
    @Id 
    @GeneratedValue 
    private int id; 
    private String foo; 
    // Setters & Getters 
} 

Теперь вы можете создать перехватчик, расширяющий Пусто перехватчик спячки и подменяет onSave метод, который устанавливает foo свойство со значением в :{id}, как это:

import java.io.Serializable; 
import org.hibernate.CallbackException; 
import org.hibernate.EmptyInterceptor; 
import org.hibernate.type.Type; 

public class MyInterceptor extends EmptyInterceptor { 

    public boolean onSave(Object entity, Serializable id, Object[] state, 
      String[] propertyNames, Type[] types) throws CallbackException { 
     System.out.println("Entered onSave : class - " + entity.getClass()); 
     if (entity instanceof Student) { 
      Student s = (Student) entity; 
      System.out.println("class:" + entity.getClass() + " , id: "+s.getId()); 
      s.setFoo(":"+id); 
     } 
     return false; 

    } 
} 

Теперь вы должны сказать зимовать в используйте этот перехватчик следующим образом:

Configuration configuration = new Configuration().setInterceptor(new LogInterceptor()); 
configuration.configure(); 
Смежные вопросы