【问题标题】:JPA2: composite keys (unable to map)JPA2:复合键(无法映射)
【发布时间】:2012-05-29 20:48:50
【问题描述】:

我正在尝试使用 JPA2 映射以下数据库结构:

ASSET
ID: assetId
...

PARTY
ID: partyId
...

PARTYASSET
ID: partyId
ID: assetId
ID: relationshipType

PARTYASSET 的主键是 PARTY 和 ASSET 的外键和一个附加列的组合:relationshipType。

由于列 relationshipType,我不能使用 @ManyToMany 注释,我必须使用 @ManyToOne 和 @OneToMany,如以下链接所述: http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany

我尝试了以下指南,但没有帮助: http://www.kawoolutions.com/Technology/JPA,_Hibernate,_and_Co./JPA_Composite_Key_Variants#JPA_2.0_@IdClass

你能帮帮我吗?

我尝试了以下方法: (继承是为了其他目的)

党课

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("PARTY")
public class Party implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long partyId;

    @OneToMany(mappedBy = "party")
    private Set<PartyAsset> partyAsset;
    ... 
}

资产类别

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("ASSET")
public class Asset implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long assetid;

    @OneToMany(mappedBy = "asset")
    private Set<PartyAsset> partyAsset;
    ...
}

使用@IdClass:

PartyAsset 类

@Entity
@IdClass(PartyAssetPK.class)
public class PartyAsset implements Serializable {
    private static final long serialVersionUID = 1L;

    public static enum RelationshipType {
        OWNER, TENANT, SECONDARY_CONTACT, SUPPLIER
    }

    @Id
    @Enumerated(EnumType.STRING)
    private RelationshipType relationshipType;

    @Id
    @ManyToOne
    @JoinColumn(name="partyId")
    private Party party;

    @Id
    @ManyToOne
    @JoinColumn(name="assetId")
    private Asset asset;
    ...
}

PartyAssetPK 类

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

    private Long partyId;
    private Long assetId;
    private PartyAsset.RelationshipType relationshipType;
}

上面的代码抛出异常:

在实体 PartyAsset 中找不到 @IdClass 的属性:assetId

@IdClass 的替代方案

PartyAsset 类

@Entity
@IdClass(PartyAssetPK.class)
public class PartyAsset implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private Long partyId;
    @Id
    private Long assetId;

    public static enum RelationshipType {
        OWNER, TENANT, SECONDARY_CONTACT, SUPPLIER
    }

    @Id
    @Enumerated(EnumType.STRING)
    private RelationshipType relationshipType;

    @ManyToOne
    @JoinColumn(name="partyId")
    @MapsId("partyId")
    private Party party;

    @ManyToOne
    @JoinColumn(name="assetId")
    @MapsId("assetId")
    private Asset asset;    
}

这会引发异常:

找不到超类型

使用@EmbeddedId

PartyAsset 类

@Entity
public class PartyAsset implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    public PartyAssetPK id;

    public static enum RelationshipType {
        OWNER, TENANT, SECONDARY_CONTACT, SUPPLIER
    }

    @MapsId("relationshipType")
    @Enumerated(EnumType.STRING)
    private RelationshipType relationshipType;

    @ManyToOne
    @JoinColumn(name="partyId")
    @MapsId("partyId")
    private Party party;

    @ManyToOne
    @JoinColumn(name="assetId")
    @MapsId("assetId")
    private Asset asset;    
}

PartyAssetPK 类

@Embeddable
public class PartyAssetPK implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long partyId;
    private Long assetId;
    private PartyAsset.RelationshipType relationshipType;
}

这会引发异常;

引起:org.springframework.beans.factory.BeanCreationException: 创建名称为“entityManagerFactoryBean”的bean时出错 班级 com.ardan1.propertymanagement.test.config.TestApplicationContext: 调用 init 方法失败;嵌套异常是 java.lang.NullPointerException 引起: java.util.Hashtable.put 处的 java.lang.NullPointerException(未知 源)在 java.util.Properties.setProperty(未知源)在 org.hibernate.cfg.annotations.SimpleValueBinder.setType(SimpleValueBinder.java:227) 在 org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:188) 在 org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:203) 在 org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2013) 在 org.hibernate.cfg.AnnotationBinder.fillComponent(AnnotationBinder.java:2385)

我有以下库(使用 Maven):

<hibernate.version>4.1.2</hibernate.version>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.2.0.Final</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.0.3.RELEASE</version>
</dependency>

【问题讨论】:

  • 这回避了问题,但您为什么不简单地为 PartyAsset 实体使用一个技术性的、非复合的、自动生成的 ID。这会容易得多!
  • 可嵌入情况下的异常是否是堆栈跟踪中最底层的部分?如果没有,请给出stacktrace中最底层的东西
  • JB Nizet,感谢您的评论。使用自动生成 ID 的简单性您可能是对的,但是,我想坚持使用数据库结构。
  • JMelnik,是的,堆栈跟踪是我控制台中出现的最后一件事。
  • 您可以将 PartyAsset 映射为组件(可嵌入),将集合映射为组件集合

标签: spring hibernate jpa jpa-2.0 spring-data-jpa


【解决方案1】:

我认为您可以使用@JoinColumn 进行映射。以下代码使用 Spring Data JPA。

BaseEntity.java

import java.io.Serializable;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.data.jpa.domain.AbstractPersistable;

public abstract class BaseEntity<PK extends Serializable> extends AbstractPersistable<PK> implements Serializable {

    private static final long serialVersionUID = 201304010827L;

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }

    @Override
    public boolean equals(Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

}

AssetEntity.java

@Entity
@Table(name = "tb_asset")
@AttributeOverride(name = "id", column = @Column(name = "AssetID"))
public class AssetEntity extends BaseEntity<Long> {

    @Column(name = "desc")
    private String desciption;

    // getters and setters...

}

PartyEntity.java

@Entity
@Table(name = "tb_party")
@AttributeOverride(name = "id", column = @Column(name = "PartyID"))
public class PartyEntity extends BaseEntity<Long> {

    private String party;

    // Getters and setters.

}

要使用@JoinColumn 和@Embeddable,我们有PartyAsset.java。

@Embeddable
public class PartyAssetKey implements Serializable {

    @ManyToOne
    @JoinColumn(name = "party_id", referencedColumnName = "id")
    private PartyEntity partyEntity;

    @ManyToOne
    @JoinColumn(name = "asset_id", referencedColumnName = "id")
    private AssetEntity assetEntity;

    private Long relationshipType;

}

最后是 PartyAssetEntity.java

@Entity
@Table(name = "tb_party_asset")
public class PartyAsset extends BaseEntity<PartyAssetKey> {

    private Long type;

    // Getters and setters.

}

我用葡萄牙语写了一篇关于 Spring Data JPA 的帖子:http://wpattern.com/blog/post/2012/11/25/Introducao-ao-Spring-Data-JPA-(Contextualizacao)-Parte-01.aspx

Cya。

【讨论】:

    【解决方案2】:

    @Techky 你通过尝试复合键的所有选项做得很好,巧合的是,我在所有场景中也遇到了完全相同的错误。

    对于使用@EmbeddedId 的情况,这是我的解决方案。这段代码我写在一个类本身中,在实体类中。

    • Class MyEntity - 这是我的表的实际实体类。 “OtherFields”是那些不属于主键的字段。
    • Class MyEntityPrimaryKeys - 这是为我的复合键创建的类,它为我的“MyEntity”类创建主键。这里 ROLLNO 和 AGE 一起构成主键。

    MyEntity.java

    @Entity
    @Table(name = "myTable")
    public class MyEntity extends GenericPersistableEntity implements Serializable {
        private static final long serialVersionUID = 1L;
    
        @EmbeddedId 
        MyEntityPrimaryKeys id;//Composite Primary key
    
        //Composite fields can be declared here for getter and setters
        @Column(name = "ROLLNO")
        private Long RollNo;
    
        //Composite fields can be declared here for getter and setters
        @Column(name = "AGE")
        private Long age;
    
        @Column(name = "OtherFields"
        private Long OtherFields;
    
        //getter and setters comes here
    }
    
    
    
    @Embeddable
     class MyEntityPrimaryKeys  implements Serializable{
    
        private static final long serialVersionUID = 1L;
    
        @Column(name = "ROLLNO")
        Long RollNo;
    
        @Column(name = "AGE")
        Long age;
    
        @Override
        public int hashCode() {
            HashCodeBuilder hcb = new HashCodeBuilder();
            hcb.append(RollNo);
            hcb.append(age);
            return hcb.toHashCode();
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof MyEntityPrimaryKeys)) {
                return false;
            }
            MyEntityPrimaryKeys that = (MyEntityPrimaryKeys) obj;
            EqualsBuilder eb = new EqualsBuilder();
            eb.append(RollNo, that.RollNo);
            eb.append(age, that.age);
            eb.append(tonMonth, that.tonMonth);
            eb.append(tonYear, that.tonYear);
            return eb.isEquals();
        }
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-28
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多