2016-05-13 2 views
2

У меня есть следующий код в классе обслуживания:JPA: слияние и сохранение контекста

public void updateEntity(Entity e){ 
    EntityManager em=entityManagerFactory.createEntityManager(); 
    em.getTransaction().begin(); 
    em.merge(e); 
    em.getTransaction().commit(); 
    em.close(); 
} 

public Entity readEntity(int id){ 
    EntityManager em=entityManagerFactory.createEntityManager(); 
    Entity result=em.find(Entity.class, id); 
    em.close(); 
    return result; 
} 

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

Так что, когда я делаю:

Entity entity=service.readEntity(100); 
entity.setXxx("lalala"); 
service.updateEntity(entity); 

Все работает как надо, и я вижу в журнале, который сгенерировал SQL изменений только одно поле. Но когда я делаю:

Entity entity=new Entity(100); 
entity.setXxx("lalala"); 
service.updateEntity(entity); 

изменения не записываются в базу данных. Пожалуйста, объясните, почему. Я использую EclipseLink.

+0

Используйте em.persist, когда у вас есть новый объект. –

+0

Если вы запустили код из своего первого теста перед вторым, тогда вызов setXxx («lalala») ничего не изменит. Проверьте значения в вашем объекте после вызова find и в объекте, который возвращается из em.merge (e) ;. Для отладки вы также можете попробовать вызов em.find перед вызовом слияния и проверить значения в возвращаемом объекте - он не должен ничего менять, если объект уже существует, так как EclipseLink будет делать то же самое в любом случае. – Chris

ответ

3

Следующая выдержка из спецификации JPA 2.0 должен дать объяснение:

Операция слияния позволяет для распространения состояния из отдельных лиц на стойких образования под управлением менеджером сущностей.

семантику операции объединения применительно к сущности X заключаются в следующем:

• Если X представляет собой отдельные лица, состояние X копируется на ранее существовавшего управляемый объект экземпляра X»одного и того же идентичность или новая управляемая копия X 'из X.

• Если X - это новый экземпляр сущности, создается новый экземпляр управляемой сущности X ', а состояние X копируется в новый экземпляр управляемой сущности X'.

• Если X является экземпляром удаленной сущности, исключение IllegalArgumentException будет выведено с помощью операции слияния (или сбой транзакции).

• Если X является управляемой сущностью, он игнорируется операцией слияния, однако операция слияния каскадируется для объектов, на которые ссылаются отношения из X, если эти отношения были аннотированы значением каскадного элемента cascade = MERGE или каскадом = ВСЕ аннотация.

• Для всех объектов Y, на которые ссылаются отношения из X, имеющие значение каскадного элемента cascade = MERGE или cascade = ALL, Y рекурсивно сливается как Y '. Для всех таких Y, на которые ссылается X, X 'устанавливается на ссылку Y'. (Обратите внимание, что если X управляется, то X - это тот же объект, что и X '.)

• Если X является сущностью, объединенной с X', со ссылкой на другой объект Y, где cascade = MERGE или cascade = ALL не указан, то навигация той же ассоциации с X «дает ссылку на управляемый объект Y» с той же постоянной идентичности как Y.

Согласно спецификации вашего Entity должны быть сохранены в базе данных. Но поскольку ваши изменения одинаковы (lalala и 100) в обоих случаях (find() затем merge() и создайте тогда merge()), возможно, вы не заметили изменений в базе данных. Я проверил следующие случаи, и все работает, как ожидалось:

  • Я создал новый объект и объединены следующим образом (это создает новую запись в базе данных с идентификатором = 101):

    @Test 
    public void createEmployee() { 
        Employee emp = new Employee(); 
        emp.setName("Test"); 
        emp.setSalary(1000); 
        tx.begin(); 
        em.merge(emp); 
        tx.commit(); 
    } 
    
  • Тогда я сделал следующее и вызывается merge(), и на этот раз только атрибут name модифицирован для объекта с ID = 101:

    @Test 
    public void createEmployee() { 
        Employee emp = new Employee(); 
        emp.setName("Test2"); 
        emp.setSalary(1000); 
        emp.setId(101); 
        tx.begin(); 
        em.merge(emp); 
        tx.commit(); 
    } 
    
Смежные вопросы