【问题标题】:Mapping a read-only database with a many-to-many relation without a join table使用多对多关系映射只读数据库而不使用连接表
【发布时间】:2011-12-23 13:19:20
【问题描述】:

我有一个类似于@ManyToMany without join table (legacy database) 的问题,还有一个问题。

我有两张桌子AB

  • A 具有多列主键(IDID2
  • B 具有多列主键(IDID3

A 中的一行可以引用B (B.ID = A.ID) 中的多行,B 中的一行可以被A 中的多行引用。

EDIT:数据库是只读的旧数据库,我无法更改。我不需要映射与 JPA 的关系(我可以在我的程序逻辑中使用额外的选择来完成),但这会很好。

它基本上是一个没有连接表的多对多关系。由于对于链接的问题,我只需要阅读表格,因此我尝试在两个类中使用两个一对多的关系。

我遇到的另一个问题是用于连接的两个IDs 都不是主键。

我有以下课程:

@Entity
@Table( name = "A" )
@IdClass( PrimaryKeysA.class )
public class A {

    @Id
    @Column( name = "ID", insertable = false, updatable = false, columnDefinition = "char" )
    private String id;

    @Id
    @Column( name = "ID2", insertable = false, updatable = false )
    private int id2;

    @OneToMany( cascade = CascadeType.ALL )
    @JoinColumn( name = "ID", columnDefinition = "char", referencedColumnName = "ID" )
    private Set< B > setOfBs;

}

@Entity
@Table( name = "B" )
@IdClass( PrimaryKeysB.class )
public class B {

    @Id
    @Column( name = "ID", insertable = false, updatable = false, columnDefinition = "char" )
    private String id;

    @Id
    @Column( name = "ID3", insertable = false, updatable = false )
    private int id3;

    @OneToMany( cascade = CascadeType.ALL )
    @JoinColumn( name = "ID", columnDefinition = "char", referencedColumnName = "ID" )
    private Set< A > setOfAs;

}

Hibernate 产生以下错误:

Exception while preparing the app : referencedColumnNames(ID) of package.B referencing package.A not mapped to a single property

我没有真正得到消息:B.id 正在引用 A (A.id) 中的单个属性。

编辑:根据要求:

public class PrimaryKeysA implements Serializable {

private static final long   serialVersionUID    = 1L;

private int    id1;
private int    id2;

    // getters/setters/equals/hashcode

}

PrimaryKeysB 类似于 id3 而不是 id2。 AB 两个类都是简化(匿名)示例。

【问题讨论】:

  • 我真的不明白这些表如何实现多对多。 A.ID 引用 B.ID,B.ID 是 B 的主键。所以一个给定的 A 只能引用一个 B。你只有一个从 A 到 B 的 ManyToOne 关联。
  • 哎呀抱歉,我在 A 上的情况与在 B 上的情况相同。我将编辑问题(我试图生成一个过于简单的示例)
  • 这不是两个表之间的多对多关联...为什么在每个表上使用两个 id?您是否有能力将此模式更改为更标准的形式,或者这是一个遗留数据库?如果它不是遗留数据库,如果您想要多对多关联,您不使用连接表的原因是什么?
  • @joncarl 不,它是一个旧的只读数据库。否则我会选择更好的设计。我也可以避免关系的映射,只定义实体。我想尝试将其映射到能够避免多次选择。
  • @joncarl,实际上是多对多关联。每个 A 有几个相关的 B,每个 B 有几个 A。设计很糟糕,但在语义上它是一个多对多的关联。

标签: java hibernate jpa


【解决方案1】:

您可以创建一个充当连接表的视图:

CREATE VIEW AJOINB AS
SELECT A.ID as AID, A.ID2 as AID2, B.ID as BID, B.ID3 as BID3
FROM A JOIN B ON A.ID = B.ID

然后在 JPA 中将其映射为以 AJOINB 作为连接表的 ManyToMany。

如果 A.ID2 和 B.ID3 本身是唯一的,那么您甚至不需要在 JPA bean 中映射 A.ID 和 B.ID。

【讨论】:

  • 由于数据库是只读的,我必须创建一个新数据库,其中包含所有表的副本以及附加视图(因为我认为我不能在数据库上定义两个实体和另一个上的连接表)。必须使用额外的数据库,然后我会尝试以更好的方式重构数据。但可能值得......
  • 取决于您的数据库。在 Oracle 和 SQL Server 中,您可以使用表别名。即使在 MySQL 中也可以创建跨方案的视图。
  • 是的,在另一个模式中创建视图是没有问题的。我担心(我没有检查)在一个模式中定义一个实体与另一个模式中的连接表将不起作用。但我将不得不使用数据库链接,因为数据库(不仅是模式)是只读的:我没有其他访问权限。
【解决方案2】:

您能分享一些表格中的示例记录吗?

问题很明确。对于任何一对多关系,在“一”方面,应该只有一个可以唯一标识的记录。在这里,我认为,因为 id 不是唯一的,所以有多个条目。

您可以尝试使用@JoinColumns 并添加两列以唯一标识“一”侧的实体。

@OneToMany
@JoinColumns({
    @JoinColumn(name="yourID1", referencedColumnName="yourID1"),
    @JoinColumn(name="yourid2", referencedColumnName="yourid2")
})

我假设您有以下数据。

表 A:

id2    c1          id
100    content1    1000
101    content2    1001

表 B:

id3    s1          id
100    content1    1000
101    content2    1000
102    content3    1001
103    content4    1001

这里 id2 和 id3 是唯一的。 A.id 是唯一的,但 b.id 不是;典型的 OneToMany 场景。

如果我使用 A.id 和 B.id 将 A 映射到 B,那么这将变成一对多,其中 A(100) 可以引用 B(100, 101),因为 id 是 1000

我认为这会很好。但是,如果您必须使用相同的列(如问题中所述)从 B 映射到 A,它将不起作用,因为一侧 (B) 有重复项。

我是否正确理解了您的问题?

【讨论】:

  • 顺便说一句,我不知道如何在不发布答案的情况下将其添加为评论。有人可以帮我吗?
  • Hibernate 在很多方面抱怨。我有一个引用 B.id1 的 A.id1。 B.id1 不是唯一的(一对多)。 Hibernate 抱怨告诉我 B.id1 是主键的一部分:但谁在乎呢。对于每个 A.id1,我有更多的 B.id1。如果 B.id1 也是 B 的主键的part,则应该不相关。表只通过id1关联(id2在B中不存在)。
  • 您的声望需要达到 50 才能发表评论
  • @Matteo 能不能把B到A的关联去掉试试,这样可以缩小问题范围?
  • 没有关联一切正常。我也可以在没有关联的情况下生活,并在选择时进行关联。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多