2014-02-17 5 views
2

Я столкнулся с какой-то странной проблемой: всякий раз, когда я пытаюсь редактировать регистр в своем приложении, а не обновлять состояние объекта, он сохраняется в новой. Вот идет мой update методJPA сохраняется, а не обновляется

public void update(Object obj) { 
    EntityManagerFactory fac = Persistence.createEntityManagerFactory("crud"); 
    EntityManager em = fac.createEntityManager(); 
    em.merge(obj); 
    em.getTransaction().begin(); 
    em.getTransaction().commit(); 
    em.close(); 
    fac.close(); 
} 

Я думаю, когда я отправить форму редактирования и сеттеры называются Id каким-то образом установить на 0. Возможно ли это произойти? Форма выглядит следующим образом:

<h:form> 
       <p:panelGrid columns="2" style="margin: 0 auto;"> 
        <f:facet name="header"> 
         Edit form 
        </f:facet> 
        Name: 
        <h:inputText id="nome" value="#{editUserBean.userToEdit.name}"/> 
        Age: 
        <h:inputText value="#{editUserBean.userToEdit.age}" converter="javax.faces.Integer"/> 
        Pass: 
        <h:inputText value="#{editUserBean.userToEdit.password}"/> 
        Gender: 
        <h:selectOneRadio value="#{editUserBean.userToEdit.gender}" style="font-size: 12px;"> 
         <f:selectItem itemValue="Masc" itemLabel="Masc" /> 
         <f:selectItem itemValue="Fem" itemLabel="Fem" /> 
        </h:selectOneRadio> 
        <f:facet name="footer"> 
         <div align="center"> 
          <h:commandButton value="save" actionListener="#{editUserBean.save}" icon="ui-icon-check"/> 
         </div> 
        </f:facet> 
       </p:panelGrid> 
</h:form> 

Hibernate запрашивает это:

Hibernate: 
    select 
     hibernate_sequence.nextval 
    from 
     dual 
Hibernate: 
    insert 
    into 
     users 
     (age, gender, name, password, id) 
    values 
     (?, ?, ?, ?, ?) 
+0

Почему вы создаете entityManager? он должен быть создан один раз для каждого экземпляра (все сеансы идут в статическом контексте). Также вместо слияния вам просто нужно упорствовать. EntityManager будет отображать уже сохраненный объект и обновляет его, если вы добавили к нему новые состояния. Но если вы создаете entityManager каждый раз, когда хотите обновлять, он не может отображать ваши уже сохраненные объекты. – solvator

+0

На самом деле я поместил его туда для названия контекста, мой EntityManager - это глобальная переменная –

+0

Итак, вы можете просто создать его в статическом блоке {}. – solvator

ответ

1

Реальная проблема заключается в слое JSF.

Все данные указывают, что editUserBean является запрос областью. Это означает, что вы получите новый компонент по запросу.

Итак, мы работаем с новымиuserToEdit bean на каждый запрос. Его свойства будут либо null, либо значением по умолчанию для примитивов (например, 0 для int и long), если вы явно не объявили значение по умолчанию для свойства внутри компонента. Это включает в себя id, который в вашем случае равен 0.

Когда вы объединяете свой bean-компонент, нет сущности с идентификатором 0 в контексте персистентности или соответствующей записи в базе данных, поэтому merge будет сохранять новый объект. Если вы генерируете значения для первичного ключа, то вероятность того, что у вас никогда не будет 0 как id, так что уровень JPA будет продолжать сохранять новые объекты.

Одно простого решение этой проблемы заключается в хранении информации о пользователе в бобе с broader scope, скажем сеанса область действия или определенный пользователь разговора области действия:

@ConversationScoped 
class UserToEdit extends User { 
    // ... or if you want, create a HAVE-A relationship 
} 

Затем вы можете придать свой компонент в качестве обычный, а сохраненный id сохранится между запросами (не забудьте очистить, правильно разграничить границы разговора и/или очистить сеансовый компонент).


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

<h:inputHidden value="#{editUserBean.userToEdit.id}" /> 

Предупреждение: Хотя этот способ является довольно популярным, только сделать это, если текущий пользователь имеет возможность обновлять информацию любого другого пользователя. Зачем? Злоумышленник может легко манипулировать DOM, чтобы изменить user.id и/или отправить поддельный запрос, содержащий любые id, чтобы злоупотреблять системой.

0

Я не знаю, если вы уже пробовали это, но проверьте конфигурационный файл спящего режима ... и затем может быть один тега содержит значение create. Измените его для обновления. Надеюсь, что это помогает

+0

Да, попробуйте, возможно, каждый раз, когда вы создаете EMF, вы удаляете данные, убедитесь, что файл конфигурации сказал, что проверка не создает. Я думаю, что это может быть проблема, очень хорошие предложения, мой друг, если он работает, рассмотрим +1 – Koitoer

+0

Нет, я использую persistence.xml. Свойство hibernate.hbm2ddl.auto настроено на обновление –

1

пару вещей ... Во-первых впрыснуть ваши PersistenceContext как это в вашем EJB:

@PersistenceContext 
private EntityManager em; 

Далее, отметьте вашу функцию, или весь EJB с правильной автоматической обработки транзакций:

@Stateless 
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public class MyServiceEJBThingy { 
    @PersistenceContext 
    private EntityManager em; 

В своем методе не делайте ничего, кроме своей бизнес-логики. sematics транзакций теперь обрабатываются для вас автоматически:

@Stateless 
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public class MyServiceEJBThingy { 
    @PersistenceContext 
    private EntityManager em; 

    public void update(Object obj) { 
     //GUI independent business logic here 
     em.merge(obj); 
    } 
} 

Наконец, теперь вводит свое EJB в контроллере представления (при условии, что вы используете шаблон MVVM):

@RequestScoped (or something) 
public class EditUserBean { 
    @Inject 
    private MyServiceEJBThingy myServiceEJBThingy; 


    public void update(Object obj) { 
     // GUI logic here 
     myServiceEJBThingy.update(obj); 
    } 
} 

Намного проще да? :) Java может быть очень простой и продуктивной. Я не уверен, какой контейнер вы используете, но я бы предложил использовать Apache TomEE. Проверьте их огромную библиотеку современных примеров here. Удачи!!!

+0

Выполнение этого. Спасибо –

+0

Если это работает, не забывайте повышать и/или принимать мои ответы и ответы других людей;) Вот как вы вознаграждаете людей за то, что помогли вам в stackoverflow :) –

+0

Как только у меня есть репутация upvote, обязательно :) –

Смежные вопросы