2016-03-12 4 views
1

У меня есть простая модель. Объект A имеет отношение «один ко многим» с объектом B. Они связаны с использованием таблицы ассоциаций. Мой вариант использования - выборка/вставка/обновление объекта в простой веб-приложении:Вставить вместо обновления с помощью данных Spring JPA

  1. Извлечь сущность A как JSON.
  2. Поместить объект A (даже без изменений) для сохранения.
  3. Нарушение ограничений: hibernate пытается вставить уже существующую строку в таблицу объединений.

Почему это происходит? В Hibernate есть все, что необходимо для определения того, следует ли выполнять слияние или сохранение на родителях и их дочерних элементах. Почему он не проверяет, связаны ли дети с родителем?

Parent.java:

package com.example; 

import java.util.HashSet; 
import java.util.Set; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.OneToMany; 
import javax.persistence.Version; 

import lombok.EqualsAndHashCode; 

@Entity 
@EqualsAndHashCode(exclude = { "id" }) 
public class Parent { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<Child> children = new HashSet<>(); 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public Set<Child> getChildren() { 
     return children; 
    } 

    public void setChildren(Set<Child> children) { 
     this.children = children; 
    } 

} 

Child.java

package com.example; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.Version; 

import lombok.EqualsAndHashCode; 

@Entity 
@EqualsAndHashCode(exclude = { "id" }) 
public class Child { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    private Long value; 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public Long getValue() { 
     return value; 
    } 

    public void setValue(Long value) { 
     this.value = value; 
    } 

} 

ParentService.java:

package com.example; 

import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 

import javax.persistence.EntityManager; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 

    @Service 
    public class ParentService { 

     @Autowired 
     private ParentRepository parentRepository; 

     @Transactional 
     public Parent save(Parent parent) { 
      return parentRepository.save(parent); 
     } 

    } 

ParentRepository.java:

package com.example; 

import org.springframework.data.jpa.repository.JpaRepository; 
import org.springframework.stereotype.Repository; 

@Repository 
public interface ParentRepository extends JpaRepository<Parent, Long>{ 

} 

Что интересно, когда я добавляю свойства @Version, тогда все работает, но я не могу найти объяснение, почему. Другим решением является выбор oldParent по id, только ради извлечения - тогда он также работает даже без @Version, но когда я получу oldParent-детей и инициализирую его с помощью size(), то снова появятся нежелательные вставки. Почему эти вещи даже работают? Это что-то связано с хранилищами Hibernate или Spring Data JPA?

+0

Вы реализовали 'equals' и' hashCode' на 'B'? –

+1

Можете ли вы предоставить некоторый код Java? – ByeBye

+0

@AliDehgani да, я сделал – Hooberd

ответ

-1

Вы писали: «Они связаны с использованием ассоциации таблицы»

Вы уверенны?

Картинка по умолчанию для ManyToOne является дополнительным внешним ключом во многих сторонах. В вашем случае дочерний элемент таблицы должен иметь дополнительное поле «parent_id», и нет дополнительной таблицы ассоциаций. Каждый ребенок может быть связан точно с одним родителем.

Возможно, вы можете разместить сообщение об исключении «hibernate пытается вставить уже существующую строку в таблицу ассоциаций»?