Java Hibernate/JPA注释中的多列联接

Java Hibernate/JPA注释中的多列联接,java,hibernate,jpa,annotations,Java,Hibernate,Jpa,Annotations,我有两个实体,我想通过多列连接它们。这些列由两个实体共享的@embeddeble对象共享。在下面的示例中,Foo只能有一个Bar,但是Bar可以有多个Foo(其中AnEmbeddableObject是Bar的唯一键)。以下是一个例子: @Entity @Table(name = "foo") public class Foo { @Id @Column(name = "id") @GeneratedValue(generator = "seqGen") @Sequ

我有两个实体,我想通过多列连接它们。这些列由两个实体共享的
@embeddeble
对象共享。在下面的示例中,
Foo
只能有一个
Bar
,但是
Bar
可以有多个
Foo
(其中
AnEmbeddableObject
Bar
的唯一键)。以下是一个例子:

@Entity
@Table(name = "foo")
public class Foo {
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddableObject anEmbeddableObject;
    @ManyToOne(targetEntity = Bar.class, fetch = FetchType.LAZY)
    @JoinColumns( {
        @JoinColumn(name = "column_1", referencedColumnName = "column_1"),
        @JoinColumn(name = "column_2", referencedColumnName = "column_2"),
        @JoinColumn(name = "column_3", referencedColumnName = "column_3"),
        @JoinColumn(name = "column_4", referencedColumnName = "column_4")
    })
    private Bar bar;

    // ... rest of class
}
和酒吧类:

@Entity
@Table(name = "bar")
public class Bar {
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddableObject anEmbeddableObject;

    // ... rest of class
}
最后,
AnEmbeddedObject
类:

@Embeddable
public class AnEmbeddedObject {
    @Column(name = "column_1")
    private Long column1;
    @Column(name = "column_2")
    private Long column2;
    @Column(name = "column_3")
    private Long column3;
    @Column(name = "column_4")
    private Long column4;

    // ... rest of class
}
显然,模式规范化程度很低,这是一个限制,即
AnEmbeddedObject
的字段在每个表中重复

我遇到的问题是,我在尝试启动Hibernate时收到此错误:

org.hibernate.AnnotationException: referencedColumnNames(column_1, column_2, column_3, column_4) of Foo.bar referencing Bar not mapped to a single property

我尝试过标记JoinColumns不可插入和更新,但运气不佳。有没有办法用Hibernate/JPA注释来表达这一点?

如果这不起作用,我就没有办法了。通过这种方式,您可以获得两个表中的4列(因为
Bar
拥有它们,并且
Foo
使用它们引用
Bar
)以及两个实体中生成的ID。4列的集合在
Bar
中必须是唯一的,因此多对一关系不会变成多对多关系

@Embeddable
public class AnEmbeddedObject
{
    @Column(name = "column_1")
    private Long column1;
    @Column(name = "column_2")
    private Long column2;
    @Column(name = "column_3")
    private Long column3;
    @Column(name = "column_4")
    private Long column4;
}

@Entity
public class Foo
{
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
        @JoinColumn(name = "column_1", referencedColumnName = "column_1"),
        @JoinColumn(name = "column_2", referencedColumnName = "column_2"),
        @JoinColumn(name = "column_3", referencedColumnName = "column_3"),
        @JoinColumn(name = "column_4", referencedColumnName = "column_4")
    })
    private Bar bar;
}

@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {
    "column_1",
    "column_2",
    "column_3",
    "column_4"
}))
public class Bar
{
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddedObject anEmbeddedObject;
}

Hibernate不会让你轻松地完成你想做的事情。从:

请注意,当对非主键列使用referencedColumnName时,关联的类必须是可序列化的还请注意,非主键列的referencedColumnName必须映射到具有单个列的属性(其他情况可能不起作用)。(重点已添加)


因此,如果您不愿意将
AnEmbeddableObject
作为Bar的标识符,那么Hibernate不会懒散地自动为您检索Bar。当然,您仍然可以使用HQL编写在
AnEmbeddableObject
上联接的查询,但是如果您坚持对Bar使用多列非主键,则会丢失自动获取和生命周期维护

这对我很有效。在我的例子中,表foo和boo必须基于3个不同的列进行连接。请注意,在我的例子中,boo中的3个公共列不是主键

i、 例如,基于3个不同列的一对一映射

@Entity
@Table(name = "foo")
public class foo implements Serializable
{
    @Column(name="foocol1")
    private String foocol1;
    //add getter setter
    @Column(name="foocol2")
    private String foocol2;
    //add getter setter
    @Column(name="foocol3")
    private String foocol3;
    //add getter setter
    private Boo boo;
    private int id;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "brsitem_id", updatable = false)
    public int getId()
    {
        return this.id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    @OneToOne
    @JoinColumns(
    {
        @JoinColumn(updatable=false,insertable=false, name="foocol1", referencedColumnName="boocol1"),
        @JoinColumn(updatable=false,insertable=false, name="foocol2", referencedColumnName="boocol2"),
        @JoinColumn(updatable=false,insertable=false, name="foocol3", referencedColumnName="boocol3")
    }
    )
    public Boo getBoo()
    {
        return boo;
    }
    public void setBoo(Boo boo)
    {
        this.boo = boo;
    }
}





@Entity
@Table(name = "boo")
public class Boo implements Serializable
{
    private int id;
    @Column(name="boocol1")
    private String boocol1;
    //add getter setter
    @Column(name="boocol2")
    private String boocol2;
    //add getter setter
    @Column(name="boocol3")
    private String boocol3;
    //add getter setter
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id", updatable = false)
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
}

这就是问题所在,“AnEmbeddedObject”必须存在于两个对象中。出于性能原因,生成的id更可取。那么4列加上生成的键映射到bar?这是非常非常糟糕的。如果您的解决方案是为
Bar
生成一个代理键,并且不在
Foo
外键中设置列,那么您必须自己设置
Foo
中的列。如果我是对的,我可以调整我的答案@bowsie我修改了我的答案,因此
Foo
Bar
都有4列,
Bar
Foo
中引用,其ID为。但这仍然不是我想要的。出于性能原因,我不想查找Bar的主id,我希望hibernate应该允许我加入任何我想要的内容-如果我两次引用列,那么将insertable和Updateable设置为false应该会起到类似于单列连接的作用。@bowsie我再次调整了答案,也许这就是你想要的?如果你从
Foo
中删除Embeddeble会怎么样?我认为这值得一试,理论上使用多个外键引用一个唯一的约束应该是可能的。如果不是这样的话,这次行动就不走运了+1因为这可能就是答案。@siebz0r,OP拍摄了这张照片,几乎完全得到了我在这种错误情况下所期望的错误消息:“referencedColumnNames…未映射到单个属性”。它应该说“没有映射到一个只有一列的属性”,但这是一样的。我想游戏结束了;-)谢谢你的信息。与此同时,我一直在使用HQL,但很好地理解了它的局限性+1在我的情况下,我想加入一列,但删除字段应为空,以便加入(我不想检索软删除的项目),如何实现这一点?