Проблема с Hibernate найти метод - PullRequest
0 голосов
/ 27 января 2010

ОБНОВЛЕНИЕ: ПРИМЕР УТОЧНИТЬ Я собираюсь привести пример того, что происходит, чтобы прояснить ситуацию в моем приложении Spring + Hibernate. Представьте, что у меня есть эти две сущности (предположим, существуют и геттеры и сеттеры)

@Entity
public class Class1(){
  private Integer id;

  @OneToOne
  private Class2 object2;
}

@Entity
public class Class2(){
  private Integer id;

  @OneToOne
  private Class1 object2;
}

Так что в моей базе данных у меня есть две таблицы для сопоставления каждого экземпляра каждого объекта. Предположим, я сохранил в базе данных эти объекты:

  • objectA (класс Class1): id = 1, object2 = objectB
  • objectB (класс Class2): id = 2, object2 = objectA
  • objectC (класс Class2): id = 3, object2 = null что означает, что A и B связаны. Предположим, теперь я хочу связать objectA с objectC. Это значит, что я тоже должен удалить ссылку в объекте.

Для этого я делаю следующее:

//I get the objectA from database
Class1 storedObjectA = myservice.find(objectAId);
//Now in storedObject1 I have the same as what it is stored as objectA

//I change only the object2 attribute of it
storedObject1.setObject2(objectC);

//I search again in the database to see objectA
Class1 reStoredObjectA = myservice.find(objectAId);

восстановленный объект теперь:

  • restoreObjectA (класс = класс1) id = 1, объект2 = объектC

хотя в базе есть:

  • restoreObjectA (class = Class1) id = 1, object2 = objectB

Метод поиска не выполнил поиск в базе данных, и я получил предыдущий поиск, хотя у меня отключены кэши запросов и второго уровня. Метод find только отправляется в DAO, где он выполняется на entityManager.find (Class1.class, id) Как мне сделать мой второй поиск в базе данных?

Спасибо


(полное объяснение)

Здравствуйте,

У меня есть приложение, которое использует Spring 3 и Hibernate. У меня есть объект с именем Class1, который хранится в базе данных. Этот объект имеет ссылку OneToOne на другой объект с именем Class2. Class2 имеет еще одну ссылку OneToOne на Class1, и обе ссылки имеют уникальное свойство, установленное в true.

У меня в контроллере следующий код:

//I have an object called dataFromUser which is instance of Class1 and
// it is obtained via @ModelAttribute annotation from a form

Integer id = dataFromUser.getId();

//I get correctly the stored object from the database
Class1 storedData = myService.find(id); //this will call em.find of hibernate

//I set to the stored data the attribute I want to change
storedData.setObject2();

//I save again the object
myService.save(storedData);

Метод save в myService будет использовать менеджер сущностей для сохранения данных, но перед этим он проверит предыдущую связь между объектом Class1 и объектом Class2, чтобы удалить их, если новый объект Class2 установил экземпляр Class1. По этой причине я должен снова вызвать метод find, чтобы увидеть, что находится в моей базе данных

В службе:

@Transactional
public void save(Class1 object1){
   Class1 objectFromDB =  myDAO.find(object1.getId());
   // ....  update the old object and save
}

Проблема в том, что objectFromDB в Сервисе отличается от того, что было в myService.find (id) в контроллере. Проблема в том, что он не ищет его в базе данных, а ищет в памяти. Я знаю это, потому что при вызове второго метода find () не регистрируется оператор SQL. Так же, как я сделал setObject2 () для объекта storeData, я получаю именно этот объект, когда я вызываю метод find во второй раз, и база данных не содержит этого, поскольку он еще не был сохранен.

Я попытался отключить кэш в своей конфигурации, просто чтобы попробовать, но это все еще происходит. У меня есть ehCache с этой конфигурацией:

В persistence.xml у меня есть эти свойства (я установил в false оба кэша):

    <properties>
     <!-- Hibernate 3.5.0 - try org.hibernate.cache.* package -->
  <property name="hibernate.cache.provider_class"
               value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
   <property name="hibernate.cache.use_query_cache" value="false" />
  <property name="hibernate.cache.use_second_level_cache" value="false" />
  <property name="hibernate.generate_statistics" value="true" />
  <property name="hibernate.cache.use_structured_entries" value="false" />
  <property name="hibernate.format_sql" value="true" />
  <!-- http://www.jroller.com/eyallupu/entry/hibernate_s_hbm2ddl_tool -->
  <!-- create, create-drop, update, validate -->
  <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>  

В моем ehcache.xml я установил 0 maxElementsInMemory и overflowToDisk в false, чтобы отключить его тоже.

Есть ли способ избежать этой ситуации?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 29 января 2010

ОК, я выяснил это. Проблема в том, что hibernate ищет объекты в своем сеансе перед поиском в базе данных. поэтому мне пришлось отсоединить объект от сеанса до его изменения. Для этого в спящем режиме:

    //being em my EntityManager instance
    Session session = (Session) em.getDelegate();
    session.evict(plan); 
    //Now the find object will not get the object wich is in session 
    //but the one in database
0 голосов
/ 27 января 2010

Я не уверен, что правильно понял, но на всякий случай ...


Существует два метода для загрузки объекта . Существует разница, если объект не находится в текущем контексте памяти:

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

Похоже, вы используете второй, может быть, вы могли бы попробовать первый и посмотреть, решит ли он вашу проблему?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...