与复合主键/外键一对多关系

时间:2019-09-05 23:03:58

标签: hibernate spring-boot jpa

我有两个实体-客户(客户)和订单(订单)。它们是一对多的-一个客户可以有多个订单,而一个订单属于一个客户。

Customer实体具有复合主键,它也是Order实体中的外键。

这是两个实体加上@IdClass:

package com.sample.test.domain.model;

import java.io.Serializable;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.Date;

@Entity
@Table(name = "Cust", schema = "test")
@IdClass(CustId.class)
public class CustEntity  implements Serializable {

  private Date deactivatedOn;
  private Integer id;
  private String name;

  public CustEntity() {
    }

  @Basic
  @Column(name = "deactivatedOn", nullable = true)
  public Date getDeactivatedOn() {
  return deactivatedOn;
  }

  public void setDeactivatedOn(Date deactivatedOn){
  this.deactivatedOn = deactivatedOn;
  }

  @Id
  @Column(name = "id", nullable = false)
  public Integer getId() {
  return id;
  }

  public void setId(Integer id){
  this.id = id;
  } 

  @Id
  @Column(name = "name", nullable = false, length =100)
  public String getName() {
  return name;
  }

  public void setName(String name){
  this.name = name;
  }

  @OneToMany(mappedBy = "cust", cascade = CascadeType.ALL, orphanRemoval = true) 
  public Set<OrdEntity> getOrdSet() { 
      return ordSet; 
  } 

  public void setOrdSet(Set<OrdEntity> ord) { 
      this.ordSet = ord; 
  } 

  private Set<OrdEntity> ordSet = new HashSet<OrdEntity>();

}




package com.sample.test.domain.model;

import java.io.Serializable;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.Date;
@Entity
@Table(name = "Ord", schema = "test")
public class OrdEntity  implements Serializable {

  private Date createdOn;
  private Date deactivatedOn;
  private Integer id;

  public OrdEntity() {
    }

  @Basic
  @Column(name = "createdOn", nullable = false)
  public Date getCreatedOn() {
  return createdOn;
  }

  public void setCreatedOn(Date createdOn){
  this.createdOn = createdOn;
  }


  @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.MERGE)
  @JoinColumns({@JoinColumn(name="custId", referencedColumnName="id", insertable = false, updatable = false),
          @JoinColumn(name="custName", referencedColumnName="name", insertable = false, updatable = false)})
  public CustEntity getCust() {
    return cust;
  }
  public void setCust(CustEntity cust) {
    this.cust = cust;
  }

  private CustEntity cust;
  @Basic
  @Column(name = "deactivatedOn", nullable = true)
  public Date getDeactivatedOn() {
  return deactivatedOn;
  }

  public void setDeactivatedOn(Date deactivatedOn){
  this.deactivatedOn = deactivatedOn;
  }

  @Id
  @Column(name = "id", nullable = false)
  public Integer getId() {
  return id;
  }

  public void setId(Integer id){
  this.id = id;
  }

}



package com.sample.test.domain.model;

import java.io.Serializable;

public class CustId implements Serializable {

    private Integer id;
    private String name;
    public CustId() {

    }
    public CustId(Integer id,String name) {
        this.id =id;
        this.name =name;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name){
        this.name = name;
    }

}

当我尝试获取客户的订单列表时,生成的休眠查询抛出异常。

这是正在生成的查询:

select ordEntity
from com.sample.test.domain.model.OrdEntity ordEntity
where ordEntity.cust.id = ?1 and ordEntity.cust.name = ?2

异常

nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: cust.id of: com.sample.test.domain.model.OrdEntity

知道为什么我会收到此异常吗?

谢谢您的帮助。

1 个答案:

答案 0 :(得分:0)

好吧,@Embeddable要容易得多,我想这就是为什么我总是使用它。

1)不能使用id关键字。

@Entity
@IdClass(CustId.class)
public class CustEntity implements Serializable {

    private Date deactivatedOn;
    private Integer val;
    private String name;

    public CustEntity() {
    }

    @Basic
    @Column(name = "deactivatedOn", nullable = true)
    public Date getDeactivatedOn() {
        return deactivatedOn;
    }

    public void setDeactivatedOn(Date deactivatedOn) {
        this.deactivatedOn = deactivatedOn;
    }

    @Id
    @Column(name = "val", nullable = false)
    public Integer getVal() {
        return val;
    }

    public void setVal(Integer val) {
        this.val = val;
    }

    @Id
    @Column(name = "name", nullable = false, length = 100)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy = "cust", cascade = CascadeType.ALL, orphanRemoval = true)
    public Set<OrdEntity> getOrdSet() {
        return ordSet;
    }

    public void setOrdSet(Set<OrdEntity> ord) {
        this.ordSet = ord;
    }

    private Set<OrdEntity> ordSet = new HashSet<OrdEntity>();

}

public class CustId implements Serializable {

    private Integer val;
    private String name;
    public CustId() {

    }
    public CustId(Integer val,String name) {
        this.val = val;
        this.name =name;
    }

    public Integer getVal() {
        return val;
    }
    public void setVal(Integer val){
        this.val = val;
    }
    public String getName() {
        return name;
    }
    public void setName(String name){
        this.name = name;
    }

}

2)无法将forein键声明为insertable = false, updatable = false

@Entity
public class OrdEntity implements Serializable {

    private Date createdOn;
    private Date deactivatedOn;
    private Integer id;

    public OrdEntity() {
    }

    @Basic
    @Column(name = "createdOn", nullable = false)
    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumns({ @JoinColumn(name = "custVal", referencedColumnName = "val"),
            @JoinColumn(name = "custName", referencedColumnName = "name") })
    public CustEntity getCust() {
        return cust;
    }

    public void setCust(CustEntity cust) {
        this.cust = cust;
    }

    private CustEntity cust;

    @Basic
    @Column(name = "deactivatedOn", nullable = true)
    public Date getDeactivatedOn() {
        return deactivatedOn;
    }

    public void setDeactivatedOn(Date deactivatedOn) {
        this.deactivatedOn = deactivatedOn;
    }

    @Id
    @Column(name = "id", nullable = false)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

}

然后它似乎可以正常工作:

tx.begin();
CustEntity cust = new CustEntity();
cust.setVal(1);
cust.setName("name");
em.persist(cust);
OrdEntity ord = new OrdEntity();
ord.setId(1);
ord.setCust(cust);
ord.setCreatedOn(Calendar.getInstance().getTime());
em.persist(ord);
tx.commit();
em.clear();

OrdEntity o = em.createQuery("select ord from OrdEntity ord where ord.cust.val = 1 and ord.cust.name = 'name'", OrdEntity.class).getSingleResult();
System.out.println(o);

给出

create table CustEntity (name varchar(100) not null, val integer not null, deactivatedOn timestamp, primary key (name, val))
Hibernate: create table CustEntity (name varchar(100) not null, val integer not null, deactivatedOn timestamp, primary key (name, val))
create table OrdEntity (id integer not null, createdOn timestamp not null, deactivatedOn timestamp, custName varchar(100), custVal integer, primary key (id))
Hibernate: create table OrdEntity (id integer not null, createdOn timestamp not null, deactivatedOn timestamp, custName varchar(100), custVal integer, primary key (id))
alter table OrdEntity add constraint FK1p8pydt8ubvr1ylolesmoxqig foreign key (custName, custVal) references CustEntity
Hibernate: alter table OrdEntity add constraint FK1p8pydt8ubvr1ylolesmoxqig foreign key (custName, custVal) references CustEntity
HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@34a97744'
Create
insert into CustEntity (deactivatedOn, name, val) values (?, ?, ?)
Hibernate: insert into CustEntity (deactivatedOn, name, val) values (?, ?, ?)
binding parameter [1] as [TIMESTAMP] - [null]
binding parameter [2] as [VARCHAR] - [name]
binding parameter [3] as [INTEGER] - [1]
insert into OrdEntity (createdOn, custName, custVal, deactivatedOn, id) values (?, ?, ?, ?, ?)
Hibernate: insert into OrdEntity (createdOn, custName, custVal, deactivatedOn, id) values (?, ?, ?, ?, ?)
binding parameter [1] as [TIMESTAMP] - [Thu Sep 05 18:05:24 MST 2019]
binding parameter [2] as [VARCHAR] - [name]
binding parameter [3] as [INTEGER] - [1]
binding parameter [4] as [TIMESTAMP] - [null]
binding parameter [5] as [INTEGER] - [1]
HHH000397: Using ASTQueryTranslatorFactory
select ordentity0_.id as id1_1_, ordentity0_.createdOn as createdO2_1_, ordentity0_.custName as custName4_1_, ordentity0_.custVal as custVal5_1_, ordentity0_.deactivatedOn as deactiva3_1_ from OrdEntity ordentity0_ cross join CustEntity custentity1_ where ordentity0_.custName=custentity1_.name and ordentity0_.custVal=custentity1_.val and custentity1_.val=1 and custentity1_.name='name'
Hibernate: select ordentity0_.id as id1_1_, ordentity0_.createdOn as createdO2_1_, ordentity0_.custName as custName4_1_, ordentity0_.custVal as custVal5_1_, ordentity0_.deactivatedOn as deactiva3_1_ from OrdEntity ordentity0_ cross join CustEntity custentity1_ where ordentity0_.custName=custentity1_.name and ordentity0_.custVal=custentity1_.val and custentity1_.val=1 and custentity1_.name='name'
extracted value ([id1_1_] : [INTEGER]) - [1]
extracted value ([createdO2_1_] : [TIMESTAMP]) - [2019-09-05 18:05:24.066]
extracted value ([custName4_1_] : [VARCHAR]) - [name]
extracted value ([custVal5_1_] : [INTEGER]) - [1]
extracted value ([deactiva3_1_] : [TIMESTAMP]) - [null]
model.OrdEntity@1e886a5b
HHH10001008: Cleaning up connection pool [jdbc:h2:mem:test]

3)使用@EmbeddedId可能不会在查询中给您cross join