繁体   English   中英

Spring Data JPA:无法使用包含外键的复合主键保存实体

[英]Spring Data JPA: Cannot save entity with composite primary key which contains foreign key

陷入困境,完全陷入困境...

假设两个实体,父级和子级,一个父级具有多个子级实体。 父级的主键的类型为java.util.UUID ,子级的主键是父级的UUID和序列号的组合。

简短的问题是,当我尝试使用childRepository.save(child)保存一个新的Child时,出现以下异常:

由以下原因引起:java.lang.IllegalArgumentException:无法将[com.package.entities.ParentEntity $$ _ jvst149_0]类型的值转换为属性“父级”的必需类型[java.util.UUID]:PropertyEditor [org.springframework.beans。 propertyeditors.UUIDEditor]返回了类型为[com.package.entities.ParentEntity _ $$ _ jvst149_0]的不合适的值

请在下面查看我的课程。 我所能告诉的最好信息是我正确地遵循了JPA规范,所以我想知道这是否是Spring Data JPA的错误,也许是UUID类型ID所特有的(以前发生过类似的事情,请参阅DATAJPA-269

注意我正在使用spring-boot-starter-data-jpa 1.4.1.RELEASE

Parent.java:

@Entity
@Table(name = "parent")
public class Parent implements Serializable {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private UUID id;

    //...other fields, getters + setters...

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Parent that = (Parent) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Child.java

@Entity
@Table(name = "child")
@IdClass(ChildKey.class)
public class Child implements Serializable {

    @Id
    @ManyToOne
    @JoinColumn(name = "parent_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Parent parent;
    @Id
    private Integer seqNum;

    //...other fields, getters + setters...

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Child that = (Child) o;
        return Objects.equals(parent, that.parent) &&
                Objects.equals(seqNum, that.seqNum);
    }

    @Override
    public int hashCode() {
        return Objects.hash(parent, seqNum);
    }
}

ChildKey.class

public class ChildKey implements Serializable {

    private UUID parent;
    private Integer seqNum;

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ChildKey that = (ChildKey) o;
        return Objects.equals(parent, that.parent) &&
                Objects.equals(seqNum, that.seqNum);
    }

    @Override
    public int hashCode() {
        return Objects.hash(parent, seqNum);
    }
}

ParentRepository.java

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

ChildRepository.java

@Repository
public interface ChildRepository extends CrudRepository<Child, ChildKey> {
}

最后,我执行的代码:

@Transactional
public void createChild(Parent parent) {
    // needed to do this to get over "detached entity passed to persist"
    parent = parentRepository.getOne(parent.getId());
    child = new Child();
    child.setParent(parent);
    child.setSeqNum(1);
    childRepository.save(child);
}

在多对一关系中,您的子实体拥有自己的ID,而来自父实体的ID是FK,而不是PK的一部分。

自发布此问题以来的几个月中,我没有找到合适的答案。 不幸的是,我不得不通过不使用@ManyToOne来解决此问题,而只是通过UUID引用父对象:

public class Child implements Serializable {

    @Id
    private UUID parentId;
    @Id
    private Integer seqNum;

我让JPA不知道外键,只是在我违反引用完整性的情况下让数据库抛出错误。

您需要更改ChildKey类:

public class ChildKey implements Serializable {

    private Parent parent; // <-- Parent type instead of UUID
    private Integer seqNum;
    ...

UPD:我阅读了JPA规范。 并理解这是不正确的。 但这对我而言有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM