虽然有一个复合主键,但只有一个键是唯一的时候,Hibernate会出错

时间:2015-11-23 11:57:06

标签: java hibernate jpa hibernate-mapping composite-primary-key

我正面临一个Hibernate错误,该错误表示找到了给定标识符的多行并且我坚持使用它。 我真的很感激任何帮助。

  • 我想创建一个表格 orderLine ,其中包含特定销售订单的产品代码,数量.etc。
  • SalesOrder 可以包含多个orderLines。

  • orderLine表的复合键是 productCode + OrderNumber 。 ProductCode是 Product 表的主键,OrderNumber是 SalesOrder 表的主键。

  • 在单个SalesOrder中,特定产品应该只有一个订单行。
  • 正确生成复合键,我得到了hibernate记录的以下sql语句。

    Hibernate:create table orderLine(orderNumber varchar(255)not null,productCode varchar(255)not null,status varchar(255)not null,quantity integer not not null,totalPrice double precision not null,unitPrice double precision not null,主键(orderNumber,productCode))

  • 当OrderLine表包含如下数据时,我成功将新记录插入OrderLine表,其中包含 OrderNumber ORD001& ProductCode BIS1003

enter image description here

  • 当我尝试从OrderLine获取记录后,我收到以下错误。

    引起:org.hibernate.HibernateException:找到了多个具有给定标识符的行:BIS1003,用于类:com.salesOrder_ws.entity.OrderLine

  • 由于复合键是主键,为什么只有复合键的一个键不唯一时,hibernate会抛出异常?

守则如下。

OrderLine实体:

  @Entity
    @Table(name = "orderLine")
    public class OrderLine implements Serializable{

    private static final long serialVersionUID = -851110991599534263L;


    @AttributeOverrides(value = 
            {@AttributeOverride(column = @Column(name="productCode"), name = "productCode"),
            @AttributeOverride(column = @Column(name="orderNumber"), name = "orderNumber")})
    @EmbeddedId
    private LineID pk;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "productCode", insertable = false, updatable = false)
    private Product product;

    private int quantity;

    private double unitPrice;

    private double totalPrice;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "orderNumber", nullable=false, insertable=false, updatable=false)
    private SalesOrder salesOrder;


    @Override
    public boolean equals(Object obj) {

        try {
            LineID line = (LineID) obj;
            return (this.getSalesOrder().getOrderNumber()
                    .equals(line.getOrderNumber()) && this.getProduct()
                    .getCode().equals(line.getProductCode()));
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return (this.getProduct().getCode() + "" + this.getProduct().getCode()).hashCode();
    }
}

SalesOrder实体

@Entity
@Table(name = "salesOrder")
public class SalesOrder extends BaseEntity{

    @Id
    private String orderNumber;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "customerCode", nullable = false)
    private Customer customer;

    private double totalPrice;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "salesOrder", cascade = CascadeType.ALL)
    private List<OrderLine> lines;


    @Override
    public boolean equals(Object obj) {

        try {
            SalesOrder so = (SalesOrder) obj;
            if (this.getOrderNumber().equals(so.getOrderNumber())) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.getOrderNumber().hashCode();
    }
}

Embeddable Class

@Embeddable
public class LineID implements Serializable{

    private static final long serialVersionUID = -4478828739881744452L;
    @Basic(optional = false)
    private String productCode;
    @Basic(optional = false)
    private String orderNumber;

    @Override
    public boolean equals(Object obj) {
        try {
            LineID l = (LineID) obj;
            return this.productCode.equals(l.getProductCode()) && this.orderNumber.equals(l.getOrderNumber());
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return (this.getOrderNumber() + "" + this.getProductCode()).hashCode();
    }
}

更新

Hibernate生成的SQL:

Hibernate: create table customer (code varchar(255) not null, status varchar(255) not null, address varchar(255), creditLimit double precision not null, currentCredit double precision not null, name varchar(255), phone1 varchar(255), phone2 varchar(255), primary key (code))
Hibernate: create table orderLine (orderNumber varchar(255), productCode varchar(255), status varchar(255) not null, quantity integer not null, totalPrice double precision not null, unitPrice double precision not null, primary key (orderNumber, productCode))
Hibernate: create table product (code varchar(255) not null, status varchar(255) not null, description varchar(255), price double precision not null, quantity integer not null, primary key (code))
Hibernate: create table salesOrder (orderNumber varchar(255) not null, status varchar(255) not null, totalPrice double precision not null, customerCode varchar(255) not null, primary key (orderNumber))
Hibernate: alter table orderLine add constraint UK_9gf3j9l0n1w7d2h4sso3voc77 unique (productCode)
Hibernate: alter table orderLine add index FK_9gf3j9l0n1w7d2h4sso3voc77 (productCode), add constraint FK_9gf3j9l0n1w7d2h4sso3voc77 foreign key (productCode) references product (code)
Hibernate: alter table orderLine add index FK_ojvge4lucwf2gtihxtmnav3u2 (orderNumber), add constraint FK_ojvge4lucwf2gtihxtmnav3u2 foreign key (orderNumber) references salesOrder (orderNumber)
Hibernate: alter table salesOrder add index FK_4lq8ynumala22y9t17ceawo81 (customerCode), add constraint FK_4lq8ynumala22y9t17ceawo81 foreign key (customerCode) references customer (code)

Hibernate:alter table orderLine add constraint UK_9gf3j9l0n1w7d2h4sso3voc77 unique(productCode)

以上SQL无意生成。如果我能避免这种独特的约束,问题就会解决。

感谢您解决此问题的任何帮助。

1 个答案:

答案 0 :(得分:1)

我认为您可能错过了@MapsId注释:

@Entity
@Table(name = "orderLine")
public class OrderLine implements Serializable{

    private static final long serialVersionUID = -851110991599534263L;

    @AttributeOverrides(value = 
            {@AttributeOverride(column = @Column(name="productCode"), name = "productCode"),
            @AttributeOverride(column = @Column(name="orderNumber"), name = "orderNumber")})
    @EmbeddedId
    private LineID pk;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("productCode")
    private Product product;

    private int quantity;

    private double unitPrice;

    private double totalPrice;

    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("orderNumber")
    private SalesOrder salesOrder;


    @Override
    public boolean equals(Object obj) {

        try {
            LineID line = (LineID) obj;
            return (this.getSalesOrder().getOrderNumber()
                    .equals(line.getOrderNumber()) && this.getProduct()
                    .getCode().equals(line.getProductCode()));
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return (this.getProduct().getCode() + "" + this.getProduct().getCode()).hashCode();
    }
}