30

我有两个实体,我想通过多个列加入。这些列@Embeddable由两个实体共享的对象共享。在下面的示例中,Foo可以只有一个BarBar可以有多个Foos(其中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

3 回答 3

18

这对我有用。在我的情况下,必须根据 3 个不同的列连接 2 个表 foo 和 boo。请注意,在我的情况下,在 boo 中,3 个常用列不是主键

即,基于 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;
    }
}
于 2013-05-16T16:38:16.557 回答
12

如果这不起作用,我就没有主意了。通过这种方式,您可以获得两个表中的 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;
}
于 2012-06-06T22:36:06.050 回答
5

Hibernate 不会让你轻松地做你想做的事情。从休眠文档

请注意,将 referencedColumnName 用于非主键列时,关联的类必须是可序列化的。另请注意,非主键列的 referencedColumnName 必须映射到具有单个列的属性(其他情况可能不起作用)。 (重点补充)

因此,如果您不愿意AnEmbeddableObject为 Bar 创建 Identifier,那么 Hibernate 不会懒惰地自动为您检索 Bar。当然,您仍然可以使用 HQL 编写 join on 的查询AnEmbeddableObject,但是如果您坚持对 Bar 使用多列非主键,则会失去自动获取和生命周期维护。

于 2012-06-14T05:32:09.980 回答