OneToMany Создать Сбои с InvalidDataAccessApiUsageException

Я довольно новичок в Hibernate и использую руководство и онлайн-форумы, но я озадачен этим вопросом. Я использую Spring 3.2 с Hibernate 4 & Annotations. У меня есть родительская (PledgeForm) и дочерняя (PledgeFormGiftLevel) таблица, которая является один ко многим.

Домен / Модели: Родитель

@Entity
@Table(name="PLEDGE_FORMS")
@SuppressWarnings("serial")
public class PledgeForm implements Serializable {

static final Logger log = Logger.getLogger(PledgeForm.class);

@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator="pledge_form_seq")
@SequenceGenerator(name="pledge_form_seq", sequenceName="PLEDGE_FORM_SEQ")
@Column(name="ID", unique=true, nullable=false)
private Integer id;

….

@OneToMany(mappedBy="pledgeForm", fetch=FetchType.EAGER, cascade=CascadeType.ALL)//********1
private List<PledgeFormGiftLevel> pledgeFormGiftLevels = new ArrayList<PledgeFormGiftLevel>();

….

public List<PledgeFormGiftLevel> getPledgeFormGiftLevels() {
   return this.pledgeFormGiftLevels;
}

public void setPledgeFormGiftLevels(List<PledgeFormGiftLevel> pledgeFormGiftLevels) {
   this.pledgeFormGiftLevels = pledgeFormGiftLevels;
}

//I do not think the following method is needed, but I decided to try it just in case
public void addPledgeFormGiftLevels(PledgeFormGiftLevel pledgeFormGiftLevels) {
   pledgeFormGiftLevels.setPledgeForm(this);
   getPledgeFormGiftLevels().add(pledgeFormGiftLevels);
}   

ребенок

@Entity
@Table(name="PLEDGE_FORM_GIFT_LEVELS")
@SequenceGenerator(name="pledge_form_gift_level_seq", sequenceName="PLEDGE_FORM_GIFT_LEVEL_SEQ")
@SuppressWarnings("serial")
public class PledgeFormGiftLevel implements Serializable {

static final Logger log = Logger.getLogger(PledgeFormGiftLevel.class);

@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator="pledge_form_gift_level_seq")
@Column(name="ID", unique=true, nullable=false)
private Integer id; 

…

@ManyToOne(fetch=FetchType.EAGER)//yes?
@JoinColumn(name="PLEDGE_FORM_ID", referencedColumnName="ID", insertable=true, updatable=true)//yes?
private PledgeForm pledgeForm = new PledgeForm();

…

public PledgeForm getPledgeForm() {
   return pledgeForm;
}
public void setPledgeForm(PledgeForm pledgeForm) {
   this.pledgeForm = pledgeForm;
}

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

@Controller
@SessionAttributes("pledgeForm")
public class PledgeFormController {
   @Autowired
   org.unctv.service.PledgeFormManager Service;

…

@RequestMapping(value = "/saveJdbcPledgeForm", method = RequestMethod.POST, params="save")
public ModelAndView save(
   @ModelAttribute("pledgeForm")
   @Valid PledgeForm pledgeForm, BindingResult result,
   @RequestParam("logoImg") MultipartFile file,
   @RequestParam(value="removeLogoImg", required=false) String removeLogoImg) throws Exception {

      ModelAndView mav = null;
      mav = new ModelAndView("pledgeFormSearch");//Name of the JSP

      if (removeLogoImg != null) {
         pledgeForm.setLogoFilename(null);

         pledgeForm.setLogoImg(null);
         pledgeForm.setLogoContentType(null);
      } else if (file != null && file.getBytes().length > 0) {
         pledgeForm.setLogoFilename(file.getOriginalFilename());
         pledgeForm.setLogoImg(file.getBytes());
         pledgeForm.setLogoContentType(file.getContentType());
      }

      Service.save(pledgeForm);
      mav.addObject("pledgeForm", pledgeForm);//JSP Form's Command Name (pledgeForm); 
      mav.addObject("cmdName", "pledgeForm");
      mav.addObject("actionType", "Save");
      return mav;
}   

Обслуживание:

@Service("simplePledgeFormManager")
@Transactional(readOnly=true)
public class SimplePledgeFormManager implements PledgeFormManager { 
   @Autowired
   private HibernatePledgeFormDao hibernatePledgeFormDao;


…

@Transactional(readOnly=false)
public void save(PledgeForm pledgeForm) throws Exception {
   hibernatePledgeFormDao.save(pledgeForm);
} 

DAO:

@Repository("PledgeFormDAO")
public class HibernatePledgeFormDao implements PledgeFormDao {

static final Logger log = Logger.getLogger(HibernatePledgeFormDao.class);

   @Autowired
   private SessionFactory sessionFactory;


...

@Override
public void save(PledgeForm pledgeForm) throws Exception {
   sessionFactory.getCurrentSession().saveOrUpdate(pledgeForm);
} 

Используя код выше, родительские / дочерние записи могут быть выбраны и обновлены в порядке. Когда я отображаю "трассировочные" сообщения из спящего режима, в обновлении появляется следующее сообщение трассировки о дочернем элементе:

[2013-12-06 10:31:24,648] TRACE Persistent instance of: org.unctv.domainmodel.PledgeFormGiftLevel
[2013-12-06 10:31:24,649] TRACE Ignoring persistent instance
[2013-12-06 10:31:24,649] TRACE Object already associated with session: [org.unctv.domainmodel.PledgeFormGiftLevel#1]

Создание всегда дает эту ошибку, если есть дочерняя запись:

object references an unsaved transient instance - save the transient instance before flushing: org.unctv.domainmodel.PledgeForm; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: org.unctv.domainmodel.PledgeForm 

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

[2013-12-06 10:34:13,615] TRACE Automatically flushing session
[2013-12-06 10:34:13,615] TRACE Flushing session
[2013-12-06 10:34:13,615] DEBUG Processing flush-time cascades
[2013-12-06 10:34:13,615] TRACE Processing cascade ACTION_SAVE_UPDATE for: org.unctv.domainmodel.PledgeForm
[2013-12-06 10:34:13,615] TRACE Cascade ACTION_SAVE_UPDATE for collection: org.unctv.domainmodel.PledgeForm.pledgeFormGiftLevels
[2013-12-06 10:34:13,615] TRACE Cascading to save or update: org.unctv.domainmodel.PledgeFormGiftLevel
[2013-12-06 10:34:13,616] TRACE Persistent instance of: org.unctv.domainmodel.PledgeFormGiftLevel
[2013-12-06 10:34:13,616] TRACE Ignoring persistent instance
[2013-12-06 10:34:13,616] TRACE Object already associated with session: [org.unctv.domainmodel.PledgeFormGiftLevel#51]
[2013-12-06 10:34:13,616] TRACE Done cascade ACTION_SAVE_UPDATE for collection: org.unctv.domainmodel.PledgeForm.pledgeFormGiftLevels
[2013-12-06 10:34:13,616] TRACE Done processing cascade ACTION_SAVE_UPDATE for: org.unctv.domainmodel.PledgeForm
[2013-12-06 10:34:13,617] DEBUG Dirty checking collections
[2013-12-06 10:34:13,617] TRACE Flushing entities and processing referenced collections
[2013-12-06 10:34:13,617] DEBUG Collection found: [org.unctv.domainmodel.PledgeForm.pledgeFormGiftLevels#51], was: [<unreferenced>] (initialized)
[2013-12-06 10:34:13,618] DEBUG rolling back
[2013-12-06 10:34:13,618] DEBUG rolled JDBC Connection 

Документация по Hibernate показывает, что это даже проще, чем мой код, но мне пришлось добавить значения fetch & cascade. Я играл с изменением значений выборки и каскада и размещения (начиная с документации Hibernate и затем добавляя), но все остальное, что я пробую, по-прежнему приводит к сбою создания и часто приводит к сбою обновления.

Многие сообщения на форуме, которые я нахожу, показывают flush() или evict(). Я не уверен, что я использую Hibernate 4 или аннотации (@Transactional, я думаю), но я не вижу места для этого в своем коде. Из журналов трассировки Hibernate я вижу, что сброс происходит автоматически с помощью метода saveOrUpdate().

Я также попытался сбросить таблицы и последовательности и начать все заново.

Любые советы о том, как заставить творение работать, приветствуются. Если вы можете указать мне на конкретную документацию, которую я пропустил, это также приветствуется.

Спасибо Бонни

1 ответ

Решение

Я заметил, что equals а также hashcode не были переопределены в объектах. Эти методы используются для сравнения объектов для определения их равенства. Hibernate, возможно, не сможет определить, существует ли существующий экземпляр сущности без переопределения этих методов. Попробуйте предоставить реализации для hashcode а также equals,

Если вы используете Eclipse, нажмите CTRL + SHIFT + S, H вызвать диалог для создания hashcode а также equals методы. Выберите поля, которые содержат значения, которые являются относительно неизменными, а затем сгенерируйте методы.

Также убедитесь, что вы управляете обеими сторонами сущности, как описано в комментариях выше:

public ModelAndView save(
   @ModelAttribute("pledgeForm")
   @Valid PledgeForm pledgeForm, BindingResult result,
   @RequestParam("logoImg") MultipartFile file,
   @RequestParam(value="removeLogoImg", required=false) String removeLogoImg) throws Exception {

      ModelAndView mav = null;
      mav = new ModelAndView("pledgeFormSearch");//Name of the JSP

      //Manage both sides of the entity
      List<PledgeFormGiftLevel> levels = pledgeForm.getPledgeFormGiftLevels();

      for(PledgeFormGiftLevel level: levels){
          level.setPledgeForm(pledgeForm);
      }

      if (removeLogoImg != null) {
         pledgeForm.setLogoFilename(null);

         pledgeForm.setLogoImg(null);
         pledgeForm.setLogoContentType(null);
      } else if (file != null && file.getBytes().length > 0) {
         pledgeForm.setLogoFilename(file.getOriginalFilename());
         pledgeForm.setLogoImg(file.getBytes());
         pledgeForm.setLogoContentType(file.getContentType());
      }

      Service.save(pledgeForm);
      mav.addObject("pledgeForm", pledgeForm);//JSP Form's Command Name (pledgeForm); 
      mav.addObject("cmdName", "pledgeForm");
      mav.addObject("actionType", "Save");
      return mav;
}   
Другие вопросы по тегам