【问题标题】:Persist 1-m entities with composite primary key in hibernate在休眠中使用复合主键持久化 1-m 实体
【发布时间】:2015-07-22 03:24:33
【问题描述】:

我与指导学生的实体的关系低于 1 米。导师有复合主键,我在学生中用作外键

@Entity
public class Mentor implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private MentorPK id;
    private String email;
    @OneToMany(mappedBy="mentor")
    private Set<Student> students;

    public MentorPK getId() {
        return id;
    }            
    //getters and setters
}

@Embeddable
public class MentorPK implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private String add;
    //getters and setters
    //override equals and hashcode
}


@Entity
public class Student implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String name;    

    @ManyToOne
    @MapsId("id")
    @JoinColumns({
        @JoinColumn(name="name_fk", referencedColumnName="name"),
        @JoinColumn(name="address_fk", referencedColumnName="address")
    })
    private Mentor mentor;

    //Getters and setters
}

然后我将上述内容保持如下,但只有导师在学生表为空的情况下保持不变。

我怎样才能让导师和学生一起坚持下去?

Set<Student> students = new HashSet<Student>();

Student s1 = new Student();
s1.setName("Student 1");

Student s2 = new Student();
s2.setName("Student 2");

students.add(s1);
students.add(s2);

MentorPK mpk = new MentorPK();
mpk.setAddress("C");
mpk.setName("D");

Mentor m = new Mentor();
m.setId(mpk);
m.setEmail("emaill");
m.setStudents(students);

studentManager.saveMentor(m);

【问题讨论】:

  • 也许这实际上是学生ID主键自动生成的问题。您可以创建没有导师的学生吗?
  • @DuncanKinnear 是的,我可以

标签: java hibernate jpa orm hibernate-mapping


【解决方案1】:

尝试将学生字段的注释更改为

@OneToMany(mappedBy="mentor", cascade = CascadeType.PERSIST)

【讨论】:

  • 添加 cascade = CascadeType.PERSIST 属性无效
  • 我刚刚使用您提供的代码创建了一个小型示例项目(修复地址/添加字段名称不一致并删除过时的@MapsId 注释)并添加级联类型,并在调用 entityManager 后按预期工作。 persist(m) 学生也被坚持。
  • 我刚刚注意到您提到了休眠,我使用 eclipselink 创建了示例。您可能想尝试使用最新版本,如果它仍然不适合您,请检查这是否是已报告的错误或您自己将其报告为错误。
  • 为什么在这种情况下CascadeType.PERSISTCascadeType.ALL 更受欢迎?根据提供的数据模型,Mentor“拥有”它们关联的Students,因此期望delete 操作也可以级联是合理的。
  • 我猜学生拥有关系知道因为外键驻留在学生方面
【解决方案2】:

当您使用复合键时,映射为 Embeddable 您需要使用@EmbeddedId

@Entity
public class Mentor {

    @EmbeddedId
    private MentorPK id;

    private String email;
    @OneToMany(mappedBy="mentor")
    private Set<Student> students;

    public MentorPK getId() {
        return id;
    }            
    //getters and setters
}

学生变成:

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String name;    

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="name_fk", referencedColumnName="name"),
        @JoinColumn(name="address_fk", referencedColumnName="address")
    })
    private Mentor mentor;

    //Getters and setters
}

@Id@ManyToOne 共享相同的数据库列时使用@MapsId,这不是你的情况,因为你有一个数字标识符和一个复合外键。

【讨论】:

    【解决方案3】:

    您可能需要在每个学生中创建从学生到导师的参考。

    因此,在您的代码中,创建 m 后,您需要:

    s1.setMentor(m);
    s2.setMentor(m);
    

    否则 Hibernate 可能不知道用什么填充列 name_fkaddress_fk

    【讨论】:

    • 也没有那样工作。我想我必须先坚持学生,然后再坚持学生的导师
    【解决方案4】:

    换个方式怎么样:

    @OneToMany(mappedBy="mentor")
    private Set<Student> students;
    

    到:

    @OneToMany(mappedBy="mentor")
    private Set<Student> students = new HashSet();
    

    @OneToMany(cascade=CascadeType.ALL)
     @JoinColumn(name="student_id")
    @org.hibernate.annotations.IndexColumn(name="idx") 
    private Set<Student> students = new HashSet();
    

    也尽量不要跳过

     = new HashSet();
    

    部分

    【讨论】:

      【解决方案5】:

      据我了解,您希望导师成为该关系的所有者。您无法通过@OneToMany(mappedBy="mentor") 行获得此信息。这实际上将学生作为关系的所有者。

      我已经测试了这个域模型并对注释进行了一些修改,以使测试代码按预期工作。

      学生

      public class Student implements Serializable {
          private static final long serialVersionUID = 1L;
          @Id
          @GeneratedValue(strategy= GenerationType.AUTO)
          private int id;
          private String name;
      
          @ManyToOne
          @JoinColumns({
                  @JoinColumn(name="name_fk", referencedColumnName="name", insertable = false, updatable = false),
                  @JoinColumn(name="address_fk", referencedColumnName="address", insertable = false, updatable = false )
          })
          private Mentor mentor;
      
      //setters and getters
      }
      

      导师

      public class Mentor implements Serializable {
          private static final long serialVersionUID = 1L;
          @Id
          private MentorPK id;
          private String email;
          @OneToMany(cascade = CascadeType.ALL)
          @JoinColumns({
                  @JoinColumn(name="name_fk", referencedColumnName="name"),
                  @JoinColumn(name="address_fk", referencedColumnName="address")
          })
          private Set<Student> students;
      //setters and getters
      }
      

      它甚至可以不做:s1.setMentor(m);s2.setMentor(m);。我没想到它,但似乎休眠正在处理这个问题。

      相关文章是here

      注意:在更改注解后删除数据库表,以便让 hibernate 重新创建表。

      【讨论】:

      • 谢谢。但实际上我希望学生成为这段关系的主人。这就是我将 mappedBy 放在 Mentor 方面的原因。所以我认为模型是正确的,但是我在客户端中保存数据的方式是错误的。你能回答如何以正确的方式坚持学生与导师吗
      • 我在下面试试,Student s1 = new Student(); s1.setName("学生 1"); MentorPK mpk = 新 MentorPK(); mpk.setAddress("C"); mpk.setName("D");导师 m = 新导师(); m.setId(mpk); m.setEmail("email"); s1.setMentor(m); //studentManager.saveMentor(m); studentManager.saveStudent(s1);但它给了我“EntityNotFoundException:无法找到 com.ejb.entities.Mentor 与 id com.ejb.entities.MentorPK@c22”。然后我在拯救学生之前坚持导师。然后我无法将 NULL 插入 ("SYS"."STUDENT"."ADDRESS_FK") 异常
      猜你喜欢
      • 2012-01-09
      • 1970-01-01
      • 2020-02-14
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 2013-08-26
      • 1970-01-01
      相关资源
      最近更新 更多