Spring-Data JPA:EntityExistsException:具有相同标识符值的不同对象

时间:2016-09-18 12:41:04

标签: jpa save spring-data

我有一个问题,我接近解决方案或更好的说我接近如何避免问题EntityExistsException: A different object with the same identifier value但不明白究竟是什么问题。为了保持代码简短和集中,我做了一个小应用程序来模拟我的项目中的问题。

首先我有一个CrudRepository始终保持不变:

public interface EntityARepository extends CrudRepository<EntityA, Long> {}

首先我需要实体,其中一个与另一个实体有关系:

@Entity
@EqualsAndHashCode(of={"name"})
@ToString(of={"name"})
@XmlRootElement
public class EntityA {

    @Id
    @GeneratedValue
    @Setter
    private Long id;

    @Setter
    @Column(nullable=false, unique=true)
    private String name;

    @Setter
    @ManyToOne(fetch=EAGER, cascade={PERSIST, MERGE})
    private EntityB entityB;

}

@ToString(of = { "name" })
@EqualsAndHashCode(of = { "name" })
@Entity
class EntityB {
    @Id
    // @GeneratedValue => produces issue!
    @Setter
    private Long id;

    @Setter
    @XmlAttribute
    @Column(nullable=false, unique=true)
    private String name;
}

然后我生成数据并尝试保存它们:

@Component
public class DatabaseInitializer implements InitializingBean {
    @Autowired EntityARepository repository;

    @Override
    public void afterPropertiesSet() throws Exception {
        final Set<EntityA> aEntities = createAEntities();
        repository.save(aEntities);
    }

    private  Set<EntityA> createAEntities() throws Exception {
        Set<EntityA> aEntities = new HashSet<>();
        aEntities.add(getFirstEntityA());
        aEntities.add(getSecondEntityA());
        return aEntities;
    }

    private EntityA getFirstEntityA(){
        EntityA a = new EntityA();
        // a.setId(1L);
        a.setName("a-1");
        a.setEntityB(getFirstEntityB());
        return a;
    }   

    private EntityA getSecondEntityA(){
        EntityA a = new EntityA();
        // a.setId(2L);
        a.setName("a-2");
        a.setEntityB(getFirstEntityB());
        return a;
    }

    private EntityB getFirstEntityB() {
        EntityB b = new EntityB();
        b.setId(1l);
        b.setName("b-1");
        return b;
    }
}

通过这种安装,我变成了EntityExistsException

Caused by: javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.example.EntityB#1]

1 个答案:

答案 0 :(得分:0)

当firstEntityA被保存时,它还会保存firstEntityB(因为级联)。因此,该会话之后已经包含了类{1}的类EntityB的实体。

当secondEntityA被持久化时,它还会调用第一个EntityB上的save,然后抛出异常。

原因是您不能在具有会话中已存在的ID的对象上调用save。

有很多方法可以修复它。例如,您可以调用merge而不是save。

    repository.merge(aEntities);

解决此问题的另一种方法是使EntityA的两个实例都具有对同一个EntityB对象的引用:

private Set<EntityA> createAEntities() throws Exception {
    Set<EntityA> aEntities = new HashSet<>();
    EntityB entityB = getFirstEntityB();
    aEntities.add(getFirstEntityA(entityB));
    aEntities.add(getSecondEntityA(entityB));
    return aEntities;
}

private EntityA getFirstEntityA(EntityB entityB){
    EntityA a = new EntityA();
    // a.setId(1L);
    a.setName("a-1");
    a.setEntityB(entityB);
    return a;
}

private EntityA getSecondEntityA(EntityB entityB){
    EntityA a = new EntityA();
    // a.setId(2L);
    a.setName("a-2");
    a.setEntityB(entityB);
    return a;
}

private EntityB getFirstEntityB() {
    EntityB b = new EntityB();
    b.setId(1l);
    b.setName("b-1");
    return b;
}