JPA授权层次结构合并导致“同一实体的多个表示”异常

时间:2016-06-27 08:05:30

标签: java jpa hibernate-cascade

我有一个实体层次结构,它在Web界面中表示和编辑,并保存在我的Web应用程序的数据层中。为了使持久化更容易,我使用CascadaType.PERSIST和CascadeType.MERGE注释了一些实体 - 但是这会导致持久化和合并的异常!

这里是实体:

  • Adresse has Land
  • Anfrage有adresse.land
  • Angebot有adresse.land和anfrage.adresse.land

实体类是从某些XML源生成的,因此很难定义哪些实体应该使用级联,哪些不应该使用级联!

@Entity
public class Adresse {
    @Id
    @Column(name = "id", nullable = false)
    @TableGenerator(name = "ids", table = "schema.ids", pkColumnName = "id_name", pkColumnValue = "ID", valueColumnName = "id", initialValue = 10000, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "ids")
    public Long getId() { return this.id; }

    @ManyToOne(fetch= FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name="land_id")
    public Land getLand() { return land; }
}

@Entity
public class Anfrage {
    @Id
    @Column(name = "id", nullable = false)
    @TableGenerator(name = "ids", table = "schema.ids", pkColumnName = "id_name", pkColumnValue = "ID", valueColumnName = "id", initialValue = 10000, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "ids")
    public Long getId() { return this.id; }

    @ManyToOne(fetch= FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name="adresse_id")
    public Adresse getAdresse() { return adresse; }
}

@Entity
public class Angebot {
    @Id
    @Column(name = "id", nullable = false)
    @TableGenerator(name = "ids", table = "schema.ids", pkColumnName = "id_name", pkColumnValue = "ID", valueColumnName = "id", initialValue = 10000, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "ids")
    public Long getId() { return this.id; }

    @ManyToOne(fetch= FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name="adresse_id")
    public Adresse getAdresse() { return adresse; }

    @ManyToOne(fetch= FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name="anfrage_id")
    public Anfrage getAnfrage() { return anfrage; }
}

这里为Anfrage服务 - 类似于Angebot和Adresse:

@DomainService
public class AnfrageService {
    @Inject protected Repository repository;

    public Anfrage getById(final Long id) {
        return repository.getEntity(this.entityClass, id);
    }

    public void save(Anfrage entity) {
        repository.save(entity);
    }

    public Anfrage update(final Anfrage entity) {
        return repository.update(entity);
    }
}

这里是存储库 - 代表数据访问层

@ApplicationScoped
@Transactional(value = Transactional.TxType.SUPPORTS)
public class Repository {
    @Inject protected EntityManager entityManager;

    public <T> T getEntity(final Class<T> clazz, final Object id) {
        return entityManager.find(clazz, id);
    }

    @Transactional(value = Transactional.TxType.REQUIRED)
    public <T> T update(T entity) {
        return entityManager.merge(entity);
    }

    @Transactional(value = Transactional.TxType.REQUIRED)
    public <T> void save(T entity) {
        entityManager.persist(entity);
    }
}

此处我的Arquillian测试 - 应用程序中出现相同的错误/异常

@Test
public void saveNewAngebotWithExistingAnfrageWithExistingAdresse() {

    final Long adresseID = 60L;
    final Long anfrageID = 8811L;

    Adresse adresse = adresseService.getById(adresseID); // -> returns adresse with land.id=1000
    Anfrage anfrage = anfrageService.getById(anfrageID); // -> anfrage also has adresse with land.id=1000

    Angebot angebot = AngebotFactory.create();
    angebot.setBeschreibung("Testangebot");

    angebot.setAdresse(adresse);
    angebot.setAnfrage(anfrage);

    angebotService.save(angebot); 

    // -> javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: 
    // detached entity passed to persist: my.domain.model.impl.Anfrage

    Angebot persistedAngebot = angebotService.update(angebot); 

    // -> java.lang.IllegalStateException: Multiple representations of the same entity 
    // [my.domain.model.impl.Land#1000] are being merged. 
    // Detached: [my.domain.model.impl.Land@273e9761[id=1000,version=6,created=17.05.2016 16:25:28,modified=17.05.2016 16:25:28,i18nKey=land.oesterreich,isoCode=AT,intVorwahl=43]]; 
    // Detached: [my.domain.model.impl.Land@7c939d12[id=1000,version=6,created=17.05.2016 16:25:28,modified=17.05.2016 16:25:28,i18nKey=land.oesterreich,isoCode=AT,intVorwahl=43]]
}

使用save / persist会导致异常,说无法保存anfrage.angebot,因为它已被分离!

使用更新/合并会导致异常,说anfrage.adresse.land和angebot.land是同一个实体,因此无法合并!

我是否必须手工处理实体层次结构的持久/合并?

我认为级联PERSIST和MERGE让事情变得更容易,但似乎更容易导致麻烦?!

我正在使用Wildfly 9,但在Wildfly 10中遇到了同样的错误!

欢迎任何提示 - 谢谢!

0 个答案:

没有答案