Hibernate将更多参数绑定到查询而不是

时间:2017-01-16 14:39:56

标签: hibernate composite-key

我坚信这是因为实体中的复合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语句不重复列。但绑定过程尝试以与先前相同的方式绑定,从而导致异常。

对你们来说,它看起来像个小虫吗?

2 个答案:

答案 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将其封装得更好。