我坚信这是因为实体中的复合ID。首先,我将展示我的情景。我有三个实体。一个使用另外两个作为ID。两者都有复合ID。
实体1(复合ID):
@Entity
@Table(name="TEST_A")
public class A implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="column1")
private int column1;
@Id
@Column(name="column2")
private int column2;
@Id
@Column(name="column3")
private int column3;
@Id
@Column(name="column4")
private int column4;
@Id
@Column(name="column5")
private int column5;
实体2(复合ID):
@Entity
@Table(name="TEST_M")
public class M implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="column1")
private int column1;
@Id
@Column(name="column2")
private int column2;
@Id
@Column(name="column3")
private int column3;
@Id
@Column(name="column6")
private int column6;
实体3(使用另外两个作为ID)
@Entity
@Table(name="TEST_F")
public class F implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumns({
@JoinColumn(name="column1", referencedColumnName="column1"), // shared
@JoinColumn(name="column2", referencedColumnName="column2"), // shared
@JoinColumn(name="column3", referencedColumnName="column3"), // shared
@JoinColumn(name="column4", referencedColumnName="column4"),
@JoinColumn(name="column5", referencedColumnName="column5")})
private A a;
@Id
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumns({
@JoinColumn(name="column1", referencedColumnName="column1"), // shared
@JoinColumn(name="column2", referencedColumnName="column2"), // shared
@JoinColumn(name="column3", referencedColumnName="column3"), // shared
@JoinColumn(name="column6", referencedColumnName="column6")})
private M m;
请注意,表 TEST_F 中的第1,2和3列用作 TEST_A 和 TEST_M 的外键。
表格:
CREATE TABLE "TEST_A"
("COLUMN1" NUMBER NOT NULL ,
"COLUMN2" NUMBER NOT NULL ,
"COLUMN3" NUMBER NOT NULL ,
"COLUMN4" NUMBER NOT NULL ,
"COLUMN5" NUMBER NOT NULL ,
CONSTRAINT "TEST_A_PK" PRIMARY KEY ("COLUMN5", "COLUMN4", "COLUMN3", "COLUMN2", "COLUMN1"));
CREATE TABLE "TEST_M"
("COLUMN1" NUMBER NOT NULL ,
"COLUMN2" NUMBER NOT NULL ,
"COLUMN3" NUMBER NOT NULL ,
"COLUMN6" NUMBER NOT NULL ,
CONSTRAINT "TEST_M_PK" PRIMARY KEY ("COLUMN1", "COLUMN2", "COLUMN6", "COLUMN3"));
CREATE TABLE "TEST_F"
("COLUMN1" NUMBER NOT NULL , -- shared by both FKs
"COLUMN2" NUMBER NOT NULL , -- shared by both FKs
"COLUMN3" NUMBER NOT NULL , -- shared by both FKs
"COLUMN4" NUMBER NOT NULL ,
"COLUMN5" NUMBER NOT NULL ,
"COLUMN6" NUMBER NOT NULL ,
CONSTRAINT "TEST_F_PK" PRIMARY KEY ("COLUMN6", "COLUMN5", "COLUMN4", "COLUMN3", "COLUMN2", "COLUMN1")
CONSTRAINT "TEST_F_M" FOREIGN KEY ("COLUMN1", "COLUMN2", "COLUMN6", "COLUMN3")
REFERENCES "TEST_M" ("COLUMN1", "COLUMN2", "COLUMN6", "COLUMN3") ENABLE,
CONSTRAINT "TEST_F_A" FOREIGN KEY ("COLUMN5", "COLUMN4", "COLUMN3", "COLUMN2", "COLUMN1")
REFERENCES "TEST_A" ("COLUMN5", "COLUMN4", "COLUMN3", "COLUMN2", "COLUMN1") ENABLE);
现在,我正在尝试做什么:
public class Main {
public static void main(String[] args) {
A a = new A();
a.setColumn1(1);
a.setColumn2(2);
a.setColumn3(3);
a.setColumn4(4);
a.setColumn5(5);
M m = new M();
m.setColumn1(1);
m.setColumn2(2);
m.setColumn3(3);
m.setColumn6(6);
F f = new F();
f.setM(m);
f.setA(a);
Session s = HibernateUtil.openSession();
Transaction tx = s.beginTransaction();
s.delete(f);
tx.commit();
}
最后,我从这一切中得到了什么:
org.hibernate.exception.GenericJDBCException: could not delete: [F#component[m,a]{a=A, m=M}]
java.sql.SQLException: Invalid column index
详细日志显示了这一点。首先它加载f:
2017-01-16 11:15:38 DEBUG org.hibernate.SQL -
/* get current state F */ select
f_.column6,
f_.column3,
f_.column2,
f_.column1,
f_.column5,
f_.column4,
f_.column3, // unnecessary
f_.column2, // unnecessary
f_.column1 // unnecessary
from
TEST_F f_
where
f_.column6=?
and f_.column3=?
and f_.column2=?
and f_.column1=?
and f_.column5=?
and f_.column4=?
and f_.column3=? // unnecessary
and f_.column2=? // unnecessary
and f_.column1=? // unnecessary
2017-01-16 11:15:38 TRACE ... - ID unsaved-value strategy UNDEFINED
2017-01-16 11:15:38 TRACE ... - binding parameter [1] as [INTEGER] - [6]
2017-01-16 11:15:38 TRACE ... - binding parameter [2] as [INTEGER] - [3]
2017-01-16 11:15:38 TRACE ... - binding parameter [3] as [INTEGER] - [2]
2017-01-16 11:15:38 TRACE ... - binding parameter [4] as [INTEGER] - [1]
2017-01-16 11:15:38 TRACE ... - ID unsaved-value strategy UNDEFINED
2017-01-16 11:15:38 TRACE ... - binding parameter [5] as [INTEGER] - [5]
2017-01-16 11:15:38 TRACE ... - binding parameter [6] as [INTEGER] - [4]
2017-01-16 11:15:38 TRACE ... - binding parameter [7] as [INTEGER] - [3] // unnecessary
2017-01-16 11:15:38 TRACE ... - binding parameter [8] as [INTEGER] - [2] // unnecessary
2017-01-16 11:15:38 TRACE ... - binding parameter [9] as [INTEGER] - [1] // unnecessary
参数绑定没问题,虽然SQL有点奇怪,因为它在select和where中重复相等的列,并且必须绑定重复的参数。
现在删除f:
2017-01-16 11:15:38 TRACE org.hibernate.persister.entity.AbstractEntityPersister - Deleting entity: [F#component[m,a]{a=A, m=M}]
2017-01-16 11:15:38 DEBUG org.hibernate.SQL -
/* delete F */ delete
from
TEST_F
where
column6=?
and column3=?
and column2=?
and column1=? // this SQL is ok, no column repetition
and column5=?
and column4=?
2017-01-16 11:15:38 TRACE ... - ID unsaved-value strategy UNDEFINED
2017-01-16 11:15:38 TRACE ... - binding parameter [1] as [INTEGER] - [6]
2017-01-16 11:15:38 TRACE ... - binding parameter [2] as [INTEGER] - [3]
2017-01-16 11:15:38 TRACE ... - binding parameter [3] as [INTEGER] - [2]
2017-01-16 11:15:38 TRACE ... - binding parameter [4] as [INTEGER] - [1]
2017-01-16 11:15:38 TRACE ... - ID unsaved-value strategy UNDEFINED
2017-01-16 11:15:38 TRACE ... - binding parameter [5] as [INTEGER] - [5]
2017-01-16 11:15:38 TRACE ... - binding parameter [6] as [INTEGER] - [4]
2017-01-16 11:15:38 TRACE ... - binding parameter [7] as [INTEGER] - [3] // trying to bind nonexistent parameter 7
2017-01-16 11:15:38 INFO ... - HHH000010: On release of batch it still contained JDBC statements
与SELECT查询不同,DELETE语句不重复列。但绑定过程尝试以与先前相同的方式绑定,从而导致异常。
对你们来说,它看起来像个小虫吗?
答案 0 :(得分:0)
我可以在映射中看到2个问题,缺少@Id
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumns({
@JoinColumn(name="column1", referencedColumnName="column1"),
@JoinColumn(name="column2", referencedColumnName="column2"),
@JoinColumn(name="column3", referencedColumnName="column3"),
@JoinColumn(name="column4", referencedColumnName="column4"),
@JoinColumn(name="column5", referencedColumnName="column5")})
private A a;
@Id
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumns({
@JoinColumn(name="column1", referencedColumnName="column1"),
@JoinColumn(name="column2", referencedColumnName="column2"),
@JoinColumn(name="column3", referencedColumnName="column3"),
@JoinColumn(name="column6", referencedColumnName="column6")})
private M m;
注释以及映射中列名称的复制
@Entity
@IdClass( value = EntityAId.class)
@Table(name = "TEST_A")
public class A implements Serializable {
@Id
@Column(name = "column1")
private int column1;
@Id
@Column(name = "column2")
private int column2;
@Id
@Column(name = "column3")
private int column3;
@Id
@Column(name = "column4")
private int column4;
@Id
@Column(name = "column5")
private int column5;
}
public class EntityAId implements Serializable{
private int column1;
private int column2;
private int column3;
private int column4;
private int column5;
}
@Entity
@IdClass( value = EntityMId.class)
@Table(name = "TEST_M")
public static class M implements Serializable {
@Id
@Column(name = "column1")
private int column1;
@Id
@Column(name = "column2")
private int column2;
@Id
@Column(name = "column3")
private int column3;
@Id
@Column(name = "column6")
private int column6;
}
public class EntityMId implements Serializable {
private int column1;
private int column2;
private int column3;
private int column6;
}
public class EntityFId implements Serializable {
private A a;
private M m;
}
@Entity
@Table(name = "TEST_F")
@IdClass( value = EntityFId.class)
public class F implements Serializable {
@Id
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumns({
@JoinColumn(name = "column1", referencedColumnName = "column1"), // shared
@JoinColumn(name = "column2", referencedColumnName = "column2"), // shared
@JoinColumn(name = "column3", referencedColumnName = "column3"), // shared
@JoinColumn(name = "column4", referencedColumnName = "column4"),
@JoinColumn(name = "column5", referencedColumnName = "column5")
})
private A a;
@Id
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumns({
@JoinColumn(name = "column6", referencedColumnName = "column1"), // shared
@JoinColumn(name = "column7", referencedColumnName = "column2"), // shared
@JoinColumn(name = "column8", referencedColumnName = "column3"), // shared
@JoinColumn(name = "column9", referencedColumnName = "column6")
})
private M m;
}
所以正确的映射是
~
答案 1 :(得分:0)
Andrea的答案很好,但@IdClass
不是使用Hibernate映射复合主键的最佳方法。
如this article所述,您应该将复合ID封装在@Embeddable
中,并使用@EmbeddedId
引用它。
在您的情况下,您有两种@Embeddable
类型:
@Embeddable
public class AId implements Serializable {
@Column(name="column1")
private int column1;
@Column(name="column2")
private int column2;
@Column(name="column3")
private int column3;
@Column(name="column4")
private int column4;
@Column(name="column5")
private int column5;
//getters and setters omitted
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof A)) return false;
A that = (A) o;
return Objects.equals(column1, that.column1) &&
Objects.equals(column2, that.column2) &&
Objects.equals(column3, that.column3) &&
Objects.equals(column4, that.column4) &&
Objects.equals(column5, that.column5);
}
@Override
public int hashCode() {
return Objects.hash(column1, column2, column3, column4, column5);
}
}
@Embeddable
public class MId implements Serializable {
@Column(name="column1")
private int column1;
@Column(name="column2")
private int column2;
@Column(name="column3")
private int column3;
@Column(name="column6")
private int column6;
//getters and setters omitted
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof A)) return false;
A that = (A) o;
return Objects.equals(column1, that.column1) &&
Objects.equals(column2, that.column2) &&
Objects.equals(column3, that.column3) &&
Objects.equals(column6, that.column6);
}
@Override
public int hashCode() {
return Objects.hash(column1, column2, column3, column6);
}
}
@Embeddable
public class FId implements Serializable {
@Column(name="column1")
private int column1;
@Column(name="column2")
private int column2;
@Column(name="column3")
private int column3;
@Column(name="column4")
private int column4;
@Column(name="column5")
private int column5;
@Column(name="column6")
private int column6;
//getters and setters omitted
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof A)) return false;
A that = (A) o;
return Objects.equals(column1, that.column1) &&
Objects.equals(column2, that.column2) &&
Objects.equals(column3, that.column3) &&
Objects.equals(column4, that.column4) &&
Objects.equals(column5, that.column5) &&;
Objects.equals(column6, that.column6);
}
@Override
public int hashCode() {
return Objects.hash(column1, column2, column3, column4, column5, column6);
}
}
然后,您的实体看起来就像那样简单:
@Entity
@Table(name="TEST_A")
public class A {
@EmbeddedId
private AId id;
}
@Entity
@Table(name="TEST_M")
public class M {
@EmbeddedId
private MId id;
}
@Entity
@Table(name="TEST_F")
public class F {
@EmbeddedId
private FId id;
}
@IdClass
要求您重复@Id
amppings,@EmbeddedId
将其封装得更好。