Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ошибка Cannot persist detached object 
V
    Опции темы
aol
Дата 23.10.2008, 21:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



используется jsf
для примера есть 2 класса, user и car, то есть один юзер имеет много машин, ну и каждая машина имеет еще много фсего в отдельной таблице, для этого сделал у нее свой id и id юзера

Код

@Entity
@Table(name = "user")
public class User implements Serializable {

@Id
@Column(name = "user_id", updatable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getUserId()       {return userId;}
...




Код

@Entity
@Table(name = "car")
public class Car implements Serializable {
private User user;
private Long userId;
private Long carId;
....
@Id
@Column(name = "car_id")
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getCarId() { return carId; }

@Column(name = "user_id", updatable = false, insertable = false)
public Long getUserId() { return userId; }

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
public User getUser()   { return user; }

public void setUser(User user)      { this.user = user; this.userId = user.getUserId(); }
....


нужно добавить новую машину к юзеру
вытаскиваю юзера из сессии и  
 
Код

     car.setUser(u);
...
      em.getTransaction().begin();
      em.persist(car);
      em.getTransaction().commit();

...
один раз вроде добавляется ок, но потом Cannot persist detached object User, бывает и тоже самое для Car
как понимаю нужно перед каждым persist делать сначала find для этого обьекта. но и он тоже выдает такую же ошибку,
как правильно работать с этими персистанс обьектами ?

спасибо


  

Это сообщение отредактировал(а) aol - 23.10.2008, 21:49
PM MAIL   Вверх
v2v
Дата 23.10.2008, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1620
Регистрация: 20.9.2006
Где: Киев

Репутация: 9
Всего: 56



Я вобще - то этой спецификацией не пользуюсь, но кажется: persist используется при создании, дальше работает merge .


--------------------
PM   Вверх
aol
Дата 23.10.2008, 23:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



merge вроде для update можно использовать, не уверен
но он тоже не работает
на форуме забугорном читал что persist да и по спецификации jpa, обьекты должны быть new, то есть новые перед каждым persist и тд.. но как их вытащить если em.find(Car.class, id) например тоже выдает ошибку такую.

PM MAIL   Вверх
powerOn
Дата 24.10.2008, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(aol @  24.10.2008,  00:55 Найти цитируемый пост)
em.find(Car.class, id) например тоже выдает ошибку такую.


Не может find такую же ошибку выдавать. Максимум IllegalArgumentException может выдать. 
Метод merge так же как и метод persist сохраняет новый объект, если он действительно новый. Из спецификации:
Цитата

• If X is a new entity instance, a new managed entity instance X' is created and the state of X is
copied into the new managed entity instance X'.


Приведите ваш код полностью.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 24.10.2008, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



прикрепил атачем, много там кода для страницы мне показалось.
класс Contract связан через форегн кей c User, работает отлично, при попытке сделать у контракта свой id и добавить поле с userId опять лезут ошибки
JPABean `инджектиться` через faces-config.xml




Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  model.zip 5,63 Kb
PM MAIL   Вверх
powerOn
Дата 24.10.2008, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Во-первых, если Вы используете EJB 3.0, то почему не инжектируете через @PersistenseContext? Быть может лучше доверить управление транзакциями контейнеру?

Во вторых, заметил у Вас часто используются подобные строки кода:
Код

        EntityManager em = jpaBean.getEMF().createEntityManager();
        Advertiser adv = null;
        try
        {
            em.getTransaction().begin();
            adv = em.find(Advertiser.class, id);
            em.refresh(adv);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return adv;


Во-вторых, зачем делать refresh после find, да еще и в отдельной транзакции? Потом, каждый раз перед новой операцией (что было также замечено в коде) создавая новый EntityManager, Вы рискуете попасть на  тот самый "detached object exception". Поскольку объект изначально был загружен в другом контексте, а значит связан с ним (с другим контекстом). При попытке вызова persist на detached объекте будет выброшено EntityExistsException. Решать такую проблему можно работая с одним экземпляром EntityManager в пределах всей бизнес-операции, т.е. методы для поиска/добавления/изменения на одном и том же экземпляре EntityManager в пределах одного (а иногда и нескольких) запросов.




 


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 25.10.2008, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



refresh в бине ContractManager в методе findContract для того чтобы после find, обновился обьект contract, так как если в базе например вручную изменить поле в данном случае готовности контракта, то без refresh он не обновляется и на экране видны старые данные.
а то что не на том месте, так это я ошибся,
наверное так надо было
Код

..
      em.getTransaction().begin();
      contract = em.find(Contract.class, userId);
      em.refresh(contract);
      em.getTransaction().commit();
..


про EntityManager не знал что нужен один для всех, поэтому я JPABean закешировал путем помещения в файле faces-config.xml

Код

..
  <managed-bean>
    <managed-bean-name>jpaBean</managed-bean-name>
    <managed-bean-class>portal.db.service.JPABean</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
  </managed-bean>


и 

Код

  <managed-bean>
    <managed-bean-name>contractManager</managed-bean-name>
    <managed-bean-class>portal.db.ContractManager</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>jpaBean</property-name>
      <value>#{jpaBean}</value>
    </managed-property>
  </managed-bean>


а потом просто брал в бинах у которых это есть это свойство

Код

EntityManager em = jpaBean.getEMF().createEntityManager();


то есть мне нужно просто перенести в эти бины обьект EntityManager, и как так обьявить ?

Код

@Stateless
public class ContractManager {

@PersistenseContext
EntityManager em;
..

  public boolean addContract(Contract contract){
    boolean ret = false;
    try{
      em.getTransaction().begin();
      em.merge(contract);
      em.getTransaction().commit();
      ret = true;
    } finally {
      em.close();
    }
    return ret;
  }

..






Это сообщение отредактировал(а) powerOn - 25.10.2008, 00:12
PM MAIL   Вверх
powerOn
Дата 25.10.2008, 00:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(aol @  25.10.2008,  01:02 Найти цитируемый пост)
refresh в бине ContractManager в методе findContract для того чтобы после find, обновился обьект contract, так как если в базе например вручную изменить поле в данном случае готовности контракта, то без refresh он не обновляется и на экране видны старые данные.


Это весьма тонкий вопрос, относящийся к параллельно выполняемым задачам. Существует ряд проблем, если планируется что несколько потоков будут одновременно использовать одни данные, например Repetable Read или Phantom Insert. Они разрешается выставлением правильного уровня изоляции для транзакционного ресурса или/и блокировками. Посмотрите вот эту статейку.

Цитата(aol @  25.10.2008,  01:02 Найти цитируемый пост)
то есть мне нужно просто перенести в эти бины обьект EntityManager, и как так обьявить ?


К сожалению, с JSF я достаточно давно работал и успел его подзабыть. Но предполагаю, что JavaEE5 контейнер должен инжектировать EJB компоненты в JSF бины через @EJB аннотацию (вроде в JSF 1.2 это получалось). Если это так, то вам следует пойти таким путем. При этом EntityManager так же будет инжектирован в Ваши EJB. Транзакции открывать и закрывать самостоятельно не нужно, это сделает за Вас контейнер. Посмотрите аннотации @TransactionAttribute.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 25.10.2008, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



не очень понял про инжектировать EJB компоненты в JSF бины. 
попробую описать как работает схема сейчас.

есть в faces-config.xml следущие записи

WelcomeBean просто класс в котором есть поле типа СontractBean

 
Код

 <managed-bean>
    <managed-bean-name>WelcomePage</managed-bean-name>
    <managed-bean-class>portal.web.bean.rumor.WelcomeBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>contractBean</property-name>
      <value>#{contractBean}</value>
    </managed-property>
  </managed-bean>


в свою очередь ContractBean содержит в себе 2 поля, contractManager как раз для работы с бд и Сontract - а это сам @Entity который и сохраняется

  
Код

<managed-bean>
    <managed-bean-name>contractBean</managed-bean-name>
    <managed-bean-class>portal.web.bean.rumor.ContractBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>contractManager</property-name>
      <value>#{contractManager}</value>
    </managed-property>
    <managed-property>
      <property-name>contract</property-name>
      <value>#{contract}</value>
    </managed-property>
  </managed-bean>


ContractManager имеет поле типа JPABean 

  
Код

<managed-bean>
    <managed-bean-name>contractManager</managed-bean-name>
    <managed-bean-class>portal.db.ContractManager</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>jpaBean</property-name>
      <value>#{jpaBean}</value>
    </managed-property>
  </managed-bean>


а JPABean имеет жизненый цикл application, то есть живет пока сервак не умрет

  
Код

<managed-bean>
    <managed-bean-name>jpaBean</managed-bean-name>
    <managed-bean-class>portal.db.service.JPABean</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
  </managed-bean>


а он просто вот что 

Код

public class JPABean {
  protected EntityManagerFactory emf;

  public EntityManagerFactory getEMF(){
    if(emf == null){
      emf = Persistence.createEntityManagerFactory("portalJPA");
    }
    return emf;
  }
}


на jsf есть такие выражения 

Код

<h:inputText value="#{WelcomePage.contractBean.contract.organizationName}" id="companyName"
                     styleClass="inputNoLabel htmlInput" required="true" requiredMessage="*"/>


когда с jsf, вызывается метод например #{WelcomePage.contractBean.createContract}
то бины и их поля которые описаны данным образом в faces-config.xml создаются так называемым путем инжектирования, 

то есть бин ContractManager имеющий у себя поле типа 

private JPABean jpaBean 
и его сеттеры и геттеры 
public JPABean getJpaBean() { return jpaBean; }
public void setJpaBean(JPABean jpaBean) { this.jpaBean = jpaBean; }

после вызова соответсвующей jsp, может обращаться у своему свойству jpaBean, что я и делаю для записи обьекта в бд, получив от jpaBean
EntityManager, EntityManager em = jpaBean.getEMF().createEntityManager();

а раз Вы говорите что EntityManager нужен для всех один, то значит мне просто нужно перенести сам EntityManager 
в бин который общается с бд, ContractManager 

@PersistenseContext
EntityManager em;

то есть эта запись равносильна EntityManager em = jpaBean.getEMF().createEntityManager(); или если напрямую то 
EntityManager em = Persistence.createEntityManagerFactory("portalJPA"); - что описано в persistace.xml ?

прощу прощения что так фсе подробно, просто сам пытаюсь понять как это все должно работать )




Это сообщение отредактировал(а) aol - 25.10.2008, 01:10
PM MAIL   Вверх
powerOn
Дата 25.10.2008, 01:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(aol @  25.10.2008,  02:09 Найти цитируемый пост)
не очень понял про инжектировать EJB компоненты в JSF бины. 


Точно так же как Вы инжектируете EntityManager в EJB компоненты с помощью аннотации @PersistenseContext, Вы можете инжектировать EJB компоненты в BackingBean-ы JSF. Проведите аналогию с инжектированием, которое происходит с JSF бинами, но только не нужно писать xml конфигурацию, контейнер получит всю необходимую информацию из аннотаций.

Еще как вариант, самостоятельно создавать новый EntityManager (как это у Вас и было), но в request scope бине. При придется самостоятельно следить за транзакциями (открывать, закрывать), а во время Unit такой подход будет лишней палкой в колесе.


Цитата(aol @  25.10.2008,  02:09 Найти цитируемый пост)
@PersistenseContext
EntityManager em;

то есть эта запись равносильна EntityManager em = jpaBean.getEMF().createEntityManager(); или если напрямую то 
EntityManager em = Persistence.createEntityManagerFactory("portalJPA"); - что описано в persistace.xml ?


Да, при этом имя персистент юнита можно указать в аннотации @PersistenseContext(unitName="portalJPA").



--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 25.10.2008, 01:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



до конца не понимаю тогда в чем будет разница, то что я сейчас создаю EntityManager из обьекта который висит постоянно в application, и что если я перенесу создание EntityManager  в сам бин только через аннотацию, то есть это одно тоже ?, и ошибка так же вылетать?

или вот еще, может тогда перенести EntityManager  в JPABean который в application, то есть он будет возвращать не EntityManagerFactory, а сразу EntityManager, причем всегда один и тот же, так как закеширован.. так правильно вообще делать ?

Это сообщение отредактировал(а) aol - 25.10.2008, 01:53
PM MAIL   Вверх
powerOn
Дата 25.10.2008, 02:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(aol @  25.10.2008,  02:50 Найти цитируемый пост)

или вот еще, может тогда перенести EntityManager  в JPABean который в application, то есть он будет возвращать не EntityManagerFactory, а сразу EntityManager, причем всегда один и тот же, так как закеширован.. так правильно вообще делать ?


В application scope его не следует создавать, ведь так к нему будут обращаться потоки параллельно из нескольких запросов, что есть плохо. Желательно, сто бы каждый request имел свой EntityManager. На крайний случай можно создавать его в Session scoped бине, но только если этого требует логика.

Цитата(aol @  25.10.2008,  02:50 Найти цитируемый пост)
до конца не понимаю тогда в чем будет разница, то что я сейчас создаю EntityManager из обьекта который висит постоянно в application, и что если я перенесу создание EntityManager  в сам бин только через аннотацию, то есть это одно тоже ?,


Если будете сами создавать EntityManager, то
Цитата(powerOn @  25.10.2008,  02:36 Найти цитируемый пост)
придется самостоятельно следить за транзакциями (открывать, закрывать), а во время Unit такой подход будет лишней палкой в колесе.




--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 25.10.2008, 02:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



ага, то есть если в бине будет 
@PersistenseContext(unitName="portalJPA")
EntityManager em;
то это значит что я его не сам создаю ?

то есть это не совсем одно и тоже как было раньше 
EntityManager em = jpaBean.getEMF().createEntityManager();
PM MAIL   Вверх
powerOn
Дата 25.10.2008, 02:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(aol @  25.10.2008,  03:23 Найти цитируемый пост)
то это значит что я его не сам создаю ?


совершенно верно. его создаст контейнер и инжектирует в бин.

p.s.: только что попробовал создать ear проект который содержит ejb модуль с EJB бином и web модуль с JSF страницей и managed bean-ом. EJB в JSF бины инжектируются, проверено.



--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
aol
Дата 25.10.2008, 02:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 23.10.2008

Репутация: нет
Всего: нет



убрал из всех бинов которые писали в бд
Код

EntityManager em = jpaBean.getEMF().createEntityManager();

и добавил к ним поле 
Код

@PersistenceContext(unitName = "portalJPA")
private EntityManager em;

из faces-config.xml тоже убрал все записи про JPABean
при попытке деплоя ear такая вот ошибка

Deploying application in domain failed; The persistence-context-ref-name [portal.db.ContractManager/em] in module [] resolves to a persistence unit called [portalJPA] which is of type RESOURCE_LOCAL. Only persistence units with transaction type JTA can be used as a container managed entity manager. Please verify your application.

вот мой persistance.xml
Код

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
  <persistence-unit name="portalJPA" transaction-type="RESOURCE_LOCAL">
    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <class>portal.model.rumor.User</class>
    <class>portal.model.rumor.document.Contract</class>
    <class>portal.model.rumor.Advertiser</class>
    <properties>
      <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/portal?characterEncoding=UTF-8"/>
      <property name="toplink.jdbc.user" value="root"/>
      <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="toplink.jdbc.password" value="1"/>
      <property name="toplink.ddl-generation" value="create-tables" />
      <property name="toplink.logging.level" value="FINE"/>
    </properties>
  </persistence-unit>
</persistence>


Это сообщение отредактировал(а) aol - 25.10.2008, 02:48
PM MAIL   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0584 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.