如何根据父级动态生成 JPA Id 列?

问题描述

我有一个看起来像这样的 JSON 文件...

{
  "accountId": "123","parties":[
    {
      "name": "John Doe"
    }
  ]
}

我可以使用类似的东西来解析这个

public class Account{
  private String id;
  @JsonProperty("parties")
  private List<Party> parties;
}

public class Party{
  private String name;
}

但是,sql 表 PARTY 包含一个复合键作为 ID。这是名称和父级帐户 ID 的复合键。有没有办法在没有单独课程的情况下做到这一点?我试过这个...

@JsonBackReference
private Account parent;

public class GetIdConverter implements AttributeConverter<String,String> {
    @Override
    public String convertToDatabaseColumn(String b) {
        if(parent == null){
            logger.error("Couldn't find the parent");
        }
        return parent.getId();
    }

    @Override
    public String convertToEntityAttribute(String s) {
        return s;
    }
}

但是当我尝试插入时,我得到...

IdentifierGenerationException:必须在调用 save() 之前手动分配此类的 ID

解决方法

不幸的是,在 JPA 中定义复合键只有两个选项:@IdClass@EmbeddedId 注释,在这两种情况下我们都必须创建一个单独的类。为复合类创建类背后的基本思想是理解我们的键包含多个主键字段并将此对象视为原子对象。将复合键作为类的想法使得在任何实现 JPA 的结构中使用实体键变得容易。

像选项一样,您可以将两个类合并为一个实体:

@Entity
@Table
@IdClass(PartyEntity.PartyId.class)
public class PartyEntity {

    public static class PartyId implements Serializable {
        private String accountId;

        private String name;

        public PartyId() {
        }

        public PartyId(String accountId,String name) {
            this.accountId = accountId;
            this.name = name;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof PartyId)) return false;
            PartyId partyId = (PartyId) o;
            return Objects.equals(accountId,partyId.accountId) &&
                    Objects.equals(name,partyId.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(accountId,name);
        }
    }

    @Id
    private String accountId;

    @Id
    private String name;

    //getters and setters
}
,

对保护程序的回答略有改进 - 您可以尝试以下映射:

public class Account{
  private String id;

  @JsonProperty("parties")
  @JsonManagedReference
  private List<Party> parties;
}

@IdClass(PartyEntity.PartyId.class)
public class Party {

    @JsonBackReference
    @Id
    @ManyToOne
    private Account account;


    @Id
    private String name;
}

请参阅 spec

的“派生标识符示例”部分中的第一个示例