【问题标题】:JPA Hibernate One-to-One relationshipJPA Hibernate 一对一关系
【发布时间】:2010-10-21 17:21:08
【问题描述】:

我有一对一的关系,但 hibernatetool 在生成架构时会抱怨。这是一个显示问题的示例:

@Entity
public class Person {
    @Id
    public int id;

    @OneToOne
    public OtherInfo otherInfo;

    rest of attributes ...
}

Person 与 OtherInfo 是一对一的关系:

@Entity
public class OtherInfo {
    @Id
    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

Person 拥有 OtherInfo 的一方。 OtherInfo 是拥有方,因此 person 使用 mappedBy 在 Person 中指定属性名称“otherInfo”。

使用 hibernatetool 生成数据库架构时出现以下错误:

org.hibernate.MappingException: Could not determine type for: Person, at table: OtherInfo, for columns: [org.hibernate.mapping.Column(person)]
        at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:292)
        at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:175)
        at org.hibernate.cfg.Configuration.iterateGenerators(Configuration.java:743)
        at org.hibernate.cfg.Configuration.generateDropSchemaScript(Configuration.java:854)
        at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:128)
        ...

知道为什么吗?是我做错了什么还是这是一个 Hibernate 错误?

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    您只需将@JoinColumn(name="column_name") 添加到主机实体关系。 column_name 是 person 表中的数据库列名。

    @Entity
    public class Person {
        @Id
        public int id;
    
        @OneToOne
        @JoinColumn(name="other_info")
        public OtherInfo otherInfo;
    
        rest of attributes ...
    }
    

    Person 与 OtherInfo 是一对一的关系: mappedBy="var_name" var_name 是 Person 类中 otherInfo 的变量名。

    @Entity
    public class OtherInfo {
        @Id
        @OneToOne(mappedBy="otherInfo")
        public Person person;
    
        rest of attributes ...
    }
    

    【讨论】:

      【解决方案2】:

      我有一个更好的方法:

      @Entity
      public class Person {
      
          @OneToOne(cascade={javax.persistence.CascadeType.ALL})
          @JoinColumn(name = "`Id_OtherInfo`")
          public OtherInfo getOtherInfo() {
            return otherInfo;
          }
      
      }
      

      就是这样

      【讨论】:

      • 也是拥有的一方,即拥有外键的一方必须实现可序列化(使用hiberate 4 /jpa 2)
      【解决方案3】:

      使用 JPA 2.0 @MapsId 注释而不是 Hibernate 的 GenericGenerator 应该也可以工作:

      @Entity
      public class Person {
      
          @Id
          @GeneratedValue
          public int id;
      
          @OneToOne
          @PrimaryKeyJoinColumn
          public OtherInfo otherInfo;
      
          rest of attributes ...
      }
      
      @Entity
      public class OtherInfo {
      
          @Id
          public int id;
      
          @MapsId
          @OneToOne
          @JoinColumn(name="id")
          public Person person;
      
          rest of attributes ...
      }
      

      Hibernate 4.1 文档第 5.1.2.2.7 节下的更多详细信息。

      【讨论】:

      • Link for the lazy。我选择在 OneToOne 类本身上使用 Id 注释(在您的示例中为 OtherInfo),但这仅适用于子父场景。感谢您的回答!
      • 为什么在OtherInfo 上指定@JoinColumn 而不是使用@PrimaryKeyJoinColumn
      【解决方案4】:

      试试这个

      @Entity
      
      @Table(name="tblperson")
      
      public class Person {
      
      public int id;
      
      public OtherInfo otherInfo;
      @Id //Here Id is autogenerated
      @Column(name="id")
      @GeneratedValue(strategy=GenerationType.AUTO)
      public int getId() {
          return id;
      }
      public void setId(int id) {
          this.id = id;
      }
      
      @OneToOne(cascade = CascadeType.ALL,targetEntity=OtherInfo.class)
      @JoinColumn(name="otherInfo_id") //there should be a column otherInfo_id in Person
      public OtherInfo getOtherInfo() {
          return otherInfo;
      }
      public void setOtherInfo(OtherInfo otherInfo) {
          this.otherInfo= otherInfo;
      }
      rest of attributes ...
      }
      
      
      @Entity
      
      @Table(name="tblotherInfo")
      
      public class OtherInfo {
      
      private int id;
      
      private Person person;
      
      @Id
      
      @Column(name="id")
      @GeneratedValue(strategy=GenerationType.AUTO)
      public Long getId() {
          return id;
      }
      public void setId(Long id) {
          this.id = id;
      }
      
        @OneToOne(mappedBy="OtherInfo",targetEntity=Person.class)   
      public College getPerson() {
          return person;
      }
      public void setPerson(Person person) {
          this.person = person;
      }    
       rest of attributes ...
      }
      

      【讨论】:

        【解决方案5】:

        JPA 不允许在 OneToOneManyToOne 映射上使用 @Id 注释。您正在尝试做的是一对一的实体关联与共享主键。最简单的情况是单向一对一共享密钥:

        @Entity
        public class Person {
            @Id
            private int id;
        
            @OneToOne
            @PrimaryKeyJoinColumn
            private OtherInfo otherInfo;
        
            rest of attributes ...
        }
        

        这样做的主要问题是 JPA 不支持 OtherInfo 实体中的共享主键生成。经典书籍Java Persistence with Hibernate by Bauer and King给出了以下使用Hibernate扩展解决问题的方法:

        @Entity
        public class OtherInfo {
            @Id @GeneratedValue(generator = "customForeignGenerator")
            @org.hibernate.annotations.GenericGenerator(
                name = "customForeignGenerator",
                strategy = "foreign",
                parameters = @Parameter(name = "property", value = "person")
            )
            private Long id;
        
            @OneToOne(mappedBy="otherInfo")
            @PrimaryKeyJoinColumn
            public Person person;
        
            rest of attributes ...
        }
        

        另外,请参阅here

        【讨论】:

        • 很好的答案,只是想补充一点,您可能还需要在您的 Person 类中添加以下注释(我必须让事情正常工作):@Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN })
        • 谢谢,它帮助解决了我的问题。你知道无论如何只使用 JPA 注释并避免使用休眠注释吗?
        • @Elton - 如果有办法,它必须在 JPA 2.0 中 - 不过我没有调查过。
        • 它确实对我有用,但我必须将 optional=false 添加到 @OneToOne 注释中。否则我会得到一个异常,抱怨那个人是空的。
        【解决方案6】:

        我认为您仍然需要 OtherInfo 类中的主键属性。

        @Entity
        public class OtherInfo {
            @Id
            public int id;
        
            @OneToOne(mappedBy="otherInfo")
            public Person person;
        
            rest of attributes ...
        }
        

        此外,您可能需要将 @PrimaryKeyJoinColumn 注释添加到映射的另一侧。我知道 Hibernate 默认使用这个。但是后来我没有使用 JPA 注释,这似乎需要您指定关联如何工作。

        【讨论】:

          【解决方案7】:

          我不确定您是否可以在 Hibernate 中将关系用作 Id/PrimaryKey。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-30
            • 2011-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多