Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用JPA和Hibernate映射复合密钥?_Java_Hibernate_Jpa_Orm_Composite Key - Fatal编程技术网

Java 如何使用JPA和Hibernate映射复合密钥?

Java 如何使用JPA和Hibernate映射复合密钥?,java,hibernate,jpa,orm,composite-key,Java,Hibernate,Jpa,Orm,Composite Key,在这段代码中,如何为组合键生成Java类(如何在hibernate中组合键): 您需要使用: 看起来你是白手起家的。尝试使用可用的反向工程工具,如数据库中的Netbeans实体,以至少实现基本的自动化(如嵌入式ID)。如果你有很多桌子,这可能会成为一个巨大的头痛。我建议避免重新发明轮子,使用尽可能多的可用工具将编码减少到最低和最重要的部分,即您想要做的事情。要映射复合键,您可以使用EmbeddedId或IdClass注释。我知道这个问题并不是关于JPA的,但是规范中定义的规则也适用。因此,它们是

在这段代码中,如何为组合键生成Java类(如何在hibernate中组合键):

您需要使用:


看起来你是白手起家的。尝试使用可用的反向工程工具,如数据库中的Netbeans实体,以至少实现基本的自动化(如嵌入式ID)。如果你有很多桌子,这可能会成为一个巨大的头痛。我建议避免重新发明轮子,使用尽可能多的可用工具将编码减少到最低和最重要的部分,即您想要做的事情。

要映射复合键,您可以使用
EmbeddedId
IdClass
注释。我知道这个问题并不是关于JPA的,但是规范中定义的规则也适用。因此,它们是:

2.1.4主键和实体标识

复合主键必须是 对应于单个 永久性字段或属性,或指向 一组字段或属性,如 如下所述。主键类 必须定义以表示 复合主键。混合成的 主键通常出现在 当 数据库密钥由几个 列嵌入ID的
IdClass
注释用于 表示复合主键。
请参阅 第9.1.14节和第9.1.15节

以下规则适用于 复合主键:

  • 主键类必须是public,并且必须具有public no arg 构造函数。
  • 如果使用基于属性的访问,则主键的属性 类必须是公共的或受保护的
  • 主键类必须是可序列化的
  • 主键类 必须定义
    等于
    hashCode
    方法。
    值的语义 必须确保这些方法的平等性 与数据库一致 对于要将 键已映射
  • 复合主键必须表示为 可嵌入类(见第9.1.14节, “EmbeddedId注释”)或必须为 表示并映射到多个 实体的字段或属性 等级(见第9.1.15节“IdClass 注释”)
  • 如果复合主键类映射到多个字段或 实体类的属性 主键字段的名称或 主键类中的属性 而实体类的那些必须 对应,其类型必须为 一样
  • 使用
    IdClass
    复合主键的类可以如下所示(可以是静态内部类):

    以及该实体:

    @Entity
    @IdClass(TimePK.class)
    class Time implements Serializable {
        @Id
        private Integer levelStation;
        @Id
        private Integer confPathID;
    
        private String src;
        private String dst;
        private Integer distance;
        private Integer price;
    
        // getters, setters
    }
    
    @Entity
    class Time implements Serializable {
        @EmbeddedId
        private TimePK timePK;
    
        private String src;
        private String dst;
        private Integer distance;
        private Integer price;
    
        //...
    }
    
    IdClass
    注释将多个字段映射到表PK

    带有
    EmbeddedId
    复合主键的类可以如下所示(可以是静态内部类):

    以及该实体:

    @Entity
    @IdClass(TimePK.class)
    class Time implements Serializable {
        @Id
        private Integer levelStation;
        @Id
        private Integer confPathID;
    
        private String src;
        private String dst;
        private Integer distance;
        private Integer price;
    
        // getters, setters
    }
    
    @Entity
    class Time implements Serializable {
        @EmbeddedId
        private TimePK timePK;
    
        private String src;
        private String dst;
        private Integer distance;
        private Integer price;
    
        //...
    }
    
    @EmbeddedId
    注释将PK类映射到表PK

    差异:
    • 从物理模型的角度来看,没有区别
    • @EmbeddedId
      以某种方式更清楚地传达了一个信息,即密钥是一个复合密钥,当组合的pk本身是一个有意义的实体或在代码中重用时,IMO是有意义的
    • @IdClass
      用于指定某些字段组合是唯一的,但这些字段没有特殊含义
    它们还影响您编写查询的方式(使查询或多或少冗长):

    • 使用
      IdClass

      select t.levelStation from Time t
      
    • 带有
      EmbeddedId

      select t.timePK.levelStation from Time t
      
    工具书类
    • JPA1.0规范
      • 第2.1.4节“主键和实体标识”
      • 第9.1.14节“嵌入式ID注释”
      • 第9.1.15节“IdClass注释”

    另一个选项是将is映射为ConfPath表中复合元素的映射

    不过,此映射将受益于(ConfPathID,levelStation)上的索引

    公共类路径{
    私有映射timeForLevelStation=newhashmap();
    公共时间getTime(长时间站){
    返回timeForLevelStation.get(levelStation);
    }
    public void putTime(long levelStation,Time newValue){
    timeForLevelStation.put(levelStation,newValue);
    }
    }
    公共课时间{
    字符串src;
    字符串dst;
    长途;
    多头价格;
    公共长途电话(){
    返回距离;
    }
    公共距离(长距离){
    这个距离=距离;
    }
    公共字符串getDst(){
    返回dst;
    }
    公共无效设置dst(字符串dst){
    this.dst=dst;
    }
    公共长期价格(){
    退货价格;
    }
    公共定价(长期价格){
    这个价格=价格;
    }
    公共字符串getSrc(){
    返回src;
    }
    公共void setSrc(字符串src){
    this.src=src;
    }
    }
    
    映射:

    <class name="ConfPath" table="ConfPath">
        <id column="ID" name="id">
            <generator class="native"/>
        </id>
        <map cascade="all-delete-orphan" name="values" table="example"
                lazy="extra">
            <key column="ConfPathID"/>
            <map-key type="long" column="levelStation"/>
            <composite-element class="Time">
                <property name="src" column="src" type="string" length="100"/>
                <property name="dst" column="dst" type="string" length="100"/>
                <property name="distance" column="distance"/>
                <property name="price" column="price"/>
            </composite-element>
        </map>
    </class>
    

    主键类必须定义equals和hashCode方法

  • 在实现equals时,应该使用instanceof来允许与子类进行比较。如果Hibernate lazy加载了一对一或多对一关系,那么您将拥有该类的代理,而不是普通类。代理是一个子类。比较类名将失败。
    更严格地说:您应该遵循Liskows替换原则,忽略对称性
  • 下一个陷阱是使用类似name.equals(that.name)的东西,而不是name.equals(that.getName())。如果是代理,第一个将失败
    让我们举一个简单的例子。假设有两个表名
    select t.timePK.levelStation from Time t
    
    public class ConfPath {
        private Map<Long,Time> timeForLevelStation = new HashMap<Long,Time>();
    
        public Time getTime(long levelStation) {
            return timeForLevelStation.get(levelStation);
        }
    
        public void putTime(long levelStation, Time newValue) {
            timeForLevelStation.put(levelStation, newValue);
        }
    }
    
    public class Time {
        String src;
        String dst;
        long distance;
        long price;
    
        public long getDistance() {
            return distance;
        }
    
        public void setDistance(long distance) {
            this.distance = distance;
        }
    
        public String getDst() {
            return dst;
        }
    
        public void setDst(String dst) {
            this.dst = dst;
        }
    
        public long getPrice() {
            return price;
        }
    
        public void setPrice(long price) {
            this.price = price;
        }
    
        public String getSrc() {
            return src;
        }
    
        public void setSrc(String src) {
            this.src = src;
        }
    }
    
    <class name="ConfPath" table="ConfPath">
        <id column="ID" name="id">
            <generator class="native"/>
        </id>
        <map cascade="all-delete-orphan" name="values" table="example"
                lazy="extra">
            <key column="ConfPathID"/>
            <map-key type="long" column="levelStation"/>
            <composite-element class="Time">
                <property name="src" column="src" type="string" length="100"/>
                <property name="dst" column="dst" type="string" length="100"/>
                <property name="distance" column="distance"/>
                <property name="price" column="price"/>
            </composite-element>
        </map>
    </class>
    
        <composite-id>
    
            <!--<key-many-to-one name="productId" class="databaselayer.users.UserDB" column="user_name"/>-->
            <key-property name="productId" column="PRODUCT_Product_ID" type="int"/>
            <key-property name="categoryId" column="categories_id" type="int" />
        </composite-id>  
    
    public  class PK implements Serializable{
        private int PRODUCT_Product_ID ;    
        private int categories_id ;
    
        public PK(int productId, int categoryId) {
            this.PRODUCT_Product_ID = productId;
            this.categories_id = categoryId;
        }
    
        public int getPRODUCT_Product_ID() {
            return PRODUCT_Product_ID;
        }
    
        public void setPRODUCT_Product_ID(int PRODUCT_Product_ID) {
            this.PRODUCT_Product_ID = PRODUCT_Product_ID;
        }
    
        public int getCategories_id() {
            return categories_id;
        }
    
        public void setCategories_id(int categories_id) {
            this.categories_id = categories_id;
        }
    
        private PK() { }
    
        @Override
        public boolean equals(Object o) {
            if ( this == o ) {
                return true;
            }
    
            if ( o == null || getClass() != o.getClass() ) {
                return false;
            }
    
            PK pk = (PK) o;
            return Objects.equals(PRODUCT_Product_ID, pk.PRODUCT_Product_ID ) &&
                    Objects.equals(categories_id, pk.categories_id );
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(PRODUCT_Product_ID, categories_id );
        }
    }
    
    @Entity(name = "product_category")
    @IdClass( PK.class )
    public  class ProductCategory implements Serializable {
        @Id    
        private int PRODUCT_Product_ID ;   
    
        @Id 
        private int categories_id ;
    
        public ProductCategory(int productId, int categoryId) {
            this.PRODUCT_Product_ID = productId ;
            this.categories_id = categoryId;
        }
    
        public ProductCategory() { }
    
        public int getPRODUCT_Product_ID() {
            return PRODUCT_Product_ID;
        }
    
        public void setPRODUCT_Product_ID(int PRODUCT_Product_ID) {
            this.PRODUCT_Product_ID = PRODUCT_Product_ID;
        }
    
        public int getCategories_id() {
            return categories_id;
        }
    
        public void setCategories_id(int categories_id) {
            this.categories_id = categories_id;
        }
    
        public void setId(PK id) {
            this.PRODUCT_Product_ID = id.getPRODUCT_Product_ID();
            this.categories_id = id.getCategories_id();
        }
    
        public PK getId() {
            return new PK(
                PRODUCT_Product_ID,
                categories_id
            );
        }    
    }
    
    @Embeddable
    public class EmployeeId implements Serializable {
     
        @Column(name = "company_id")
        private Long companyId;
     
        @Column(name = "employee_number")
        private Long employeeNumber;
     
        public EmployeeId() {
        }
     
        public EmployeeId(Long companyId, Long employeeId) {
            this.companyId = companyId;
            this.employeeNumber = employeeId;
        }
     
        public Long getCompanyId() {
            return companyId;
        }
     
        public Long getEmployeeNumber() {
            return employeeNumber;
        }
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof EmployeeId)) return false;
            EmployeeId that = (EmployeeId) o;
            return Objects.equals(getCompanyId(), that.getCompanyId()) &&
                    Objects.equals(getEmployeeNumber(), that.getEmployeeNumber());
        }
     
        @Override
        public int hashCode() {
            return Objects.hash(getCompanyId(), getEmployeeNumber());
        }
    }
    
    @Entity(name = "Employee")
    @Table(name = "employee")
    public class Employee {
     
        @EmbeddedId
        private EmployeeId id;
     
        private String name;
     
        public EmployeeId getId() {
            return id;
        }
     
        public void setId(EmployeeId id) {
            this.id = id;
        }
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
    }
    
    @Entity(name = "Phone")
    @Table(name = "phone")
    public class Phone {
     
        @Id
        @Column(name = "`number`")
        private String number;
     
        @ManyToOne
        @JoinColumns({
            @JoinColumn(
                name = "company_id",
                referencedColumnName = "company_id"),
            @JoinColumn(
                name = "employee_number",
                referencedColumnName = "employee_number")
        })
        private Employee employee;
     
        public Employee getEmployee() {
            return employee;
        }
     
        public void setEmployee(Employee employee) {
            this.employee = employee;
        }
     
        public String getNumber() {
            return number;
        }
     
        public void setNumber(String number) {
            this.number = number;
        }
    }