【问题标题】:JPA and Hibernate One To One Shared Primary Key Uni-directional Mapping in Spring BootSpring Boot中JPA和Hibernate一对一共享主键单向映射
【发布时间】:2021-05-26 12:25:40
【问题描述】:

我希望使用共享主键与 2 个子实体进行一对一的单向映射。以下是模型类

public class Template implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "templatekey")
    Integer templateKey;

    @Column(name = "templateid", unique = true)
    String templateId;
    
    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @PrimaryKeyJoinColumn(name = "templatekey", referencedColumnName = "templatekey")
    InstantOfferNoEsp instantOfferNoEsp;

    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @PrimaryKeyJoinColumn(name = "templatekey", referencedColumnName = "templatekey")
    Mobile mobile;

     //constructor , setter and getters

}

Child 1 :

public class Mobile implements Serializable {
   
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "templatekey")
    Integer templateKey;
    
    String mobileNewUrl;


    //constructor , setter and getters

}

Child 2:

public class InstantOfferNoEsp {

    @Id
    @Column(name = "templatekey")
    Integer templateKey;

    String offerCodeType;

    String headerUrl;
 
    //constructor , setter and getters
}

我希望 templateKey 在所有表中都作为 PK。我正在调用templateRepository.save(template); 来一次保存所有实体,但它不起作用并出现ids for this class must be manually assigned before calling save() 错误。

任何建议都会有很大帮助。谢谢。

【问题讨论】:

  • 您能否具体说明您要为templateKey - IDENTITYSEQUENCE 使用什么实际生成策略?
  • 我想在父(模板)中使用strategy = GenerationType.AUTO...并且应该在孩子之间共享
  • 查看documentation。很难猜测它将如何解释。这将取决于休眠版本/休眠配置(您是否使用 hibernate.id.new_generator_mappings),数据库您使用什么
  • 我正在使用 mysql 数据库,它使用 hibernate_sequence 来获取 Id

标签: spring-boot hibernate jpa spring-data-jpa jpa-2.1


【解决方案1】:

我可以用双向@OneToOne 做你想做的事,如下所示:

@Entity
public class Mobile {

    @Id
    Integer templateKey;
    
    @OneToOne
    @MapsId
    @JoinColumn(name = "templatekey")
    Template template;

    // ...
}

@Entity
public class InstantOfferNoEsp {

    @Id
    Integer templateKey;

    @OneToOne
    @MapsId
    @JoinColumn(name = "templatekey")
    Template template;
 
    // ...
}


@Entity
public class Template {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "templatekey")
    Integer templateKey;

    
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "template", optional = false)
    InstantOfferNoEsp instantOfferNoEsp;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "template", optional = false)
    Mobile mobile;

    // ...

    public void setMobile(Mobile mobile)
    {
        this.mobile = mobile;
        this.mobile.setTemplate(this);
    }

    public void setInstantOfferNoEsp(InstantOfferNoEsp instantOfferNoEsp)
    {
        this.instantOfferNoEsp = instantOfferNoEsp;
        this.instantOfferNoEsp.setTemplate(this);
    }
}

还有一个保存的例子:

Mobile mobile = new Mobile();
mobile.setMobileNewUrl("MOB1");

InstantOfferNoEsp instant = new InstantOfferNoEsp();
instant.setOfferCodeType("INST_OFF1");
      
Template template = new Template();
template.setTemplateId("TMP1");
template.setInstantOffer(instant);
template.setMobile(mobile);
entityManager.persist(template);

附:以下映射也有效,但前提是我们手动设置 Template.templateKey

@Entity
public class Template
{
   @Id
   // @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "templatekey")
   Integer templateKey;

   @OneToOne(cascade = CascadeType.ALL, optional = false)
   @JoinColumn(name = "templatekey", insertable = false, updatable = false)
   InstantOfferNoEsp instantOfferNoEsp;

   @OneToOne(cascade = CascadeType.ALL, optional = false)
   @JoinColumn(name = "templatekey", insertable = false, updatable = false)
   Mobile mobile;
 
   // ...
}

还有一个保存的例子:

Mobile mobile = new Mobile();
mobile.setMobileNewUrl("MOB1");

InstantOfferNoEsp instant = new InstantOfferNoEsp();
instant.setOfferCodeType("INST_OFF1");
      
Template template = new Template();
template.setTemplateKey(20);
template.setTemplateId("TMP1");
template.setInstantOffer(instant);
template.setMobile(mobile);
entityManager.persist(template);

另外我建议您明确指定要使用的生成策略(不要使用GenerationType.AUTO)并使用相应的对象包装类而不是@Id 字段的原始类型。

【讨论】:

  • 我仍然遇到同样的错误。 org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.xxx.xxx.model.Mobile while calling templateRepository.save(template). 我们是否需要手动持久化父级,然后将父级的 id 传递给子级
  • 尝试使用更新答案中的映射
  • 如果您可以接受双向@OneToOne,请尝试使用更新后的答案中的映射。
  • 谢谢斯特恩...我们同意使用双向,您的解决方案正在运行。
猜你喜欢
  • 2011-06-12
  • 2020-03-09
  • 2014-11-22
  • 2020-12-17
  • 1970-01-01
  • 1970-01-01
  • 2016-09-18
  • 2011-05-08
  • 1970-01-01
相关资源
最近更新 更多