【问题标题】:Accessing multiple tables访问多个表
【发布时间】:2012-08-14 15:59:21
【问题描述】:

我正在学习 EJB,JPA 并且有非常基本的疑问

我有 3 张桌子 A、B、C

A - ID、姓名

B - ID、姓名

C - ID、A_ID、B_ID

当我从数据库创建实体类时,我得到 3 个带有 JPA 内容的 EJB 类。

现在在我的托管 bean 中,我得到 A.Name 或 B.Name,我需要使用 C 查找匹配的条目。

普通 SQL 查询看起来像(可能不是最好的查询)

SELECT a.name FROM schema.A a, schema.B b, schema.C c where b.Name='ABC' and c.B_ID=b.ID and a.ID = c.A_ID;

现在我在哪里可以在我的课程中进行上述查询。

我遇到了@SecondaryTable,但不明白它是如何使用的。

我还看到了 em.createQuery(SQL query).getResultList()。

现在是上面最好的方法,或者 EJB/JPA 中是否有更好的方法。

更新 1:

我试图在 em.CreateQuery 中执行查询

em.CreateQuery(SELECT a.name FROM A a, B b, C c where b.Name='ABC' and c.B_ID=b.ID and a.ID = c.A_ID).getResultList();

但我的 GlassFish Server 中出现以下错误(我正在使用 EcipeLink JPA)

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: syntax error at or near ")"
  Position: 
Error Code: 0
Call: SELECT t0.given_name FROM test.a t3, test.a_b t2, test.b t1, test.a t0 WHERE ((((t1.Name = ?) AND (t2.b_id = t1.id.t1.id)) AND (t0.id = )) AND (t3.id = t2.a_id))
bind => [1 parameter bound]
Query: ReportQuery(referenceClass=Consultant sql="SELECT t0.given_name FROM test.a t3, test.a_b t2, test.b t1, test.a t0 WHERE ((((t1.Name = ?) AND (t2.b_id = t1.id.t1.id)) AND (t0.id = )) AND (t3.id = t2.a_id))")

现在为什么 SQl 语句在错误日志中被弄乱了

1.有一个额外的入口test.a t0

2.t2.b_id = t1.id.t1.id

3.t0.id=

错误日志SQL语句是如何生成的。

【问题讨论】:

  • C 真的应该成为一个实体还是只是用来在 A 和 B 之间建立多对多关系?
  • C 用于多对多关系
  • 您需要显示实体中的映射,并可能将 EclipseLink 日志记录设置为最好,以查看可能发生的情况。导致错误的 SQL 语句不应直接从所示的 JPQL 查询创建,因为它有一个与 A 的 id 绑定的参数。

标签: java jpa-2.0 eclipselink ejb-3.1


【解决方案1】:

由于 C 是 A 和 B 之间的多对多关系,因此它不应该是一个实体。但是,我认为 JPA 不喜欢您的连接表 (C) 有它自己的 ID 列。如果可能,请从 C 中删除 ID 列,并将 A_ID、B_ID 的组合作为主键。

那么实体类A可以有:

@JoinTable(name = "C",
    joinColumns = { @JoinColumn(name = "A_ID", referencedColumnName = "ID") },
    inverseJoinColumns = { @JoinColumn(name = "B_ID", referencedColumnName = "ID") })
@ManyToMany
private Collection<B> bCollection;

我认为所有这些注释的含义都很清楚。 B 类会:

@ManyToMany(mappedBy = "bCollection") 
private Collection<A> aCollection;

mappedBy 属性告诉 JPA 使用 A::bCollection 的 JoinTable 定义(A 是从字段的类型 Collection 推导出来的)。

现在,如果您有 A 的实例,您可以通过获取属性轻松获取该 A 的所有 B。不需要任何 SQL/JPQL。

现在关于执行查询,您应该知道您有 JPQL 和 SQL。 JPQL 是 Java 持久性查询语言,是 JPA 的语言。 SQL 是数据库的母语。要执行 SQL,您需要使用 createNativeQuery 系列函数。 createQuery 函数适用于 JPQL。

您应该更喜欢 JPQL 而不是 SQL。两者之间最重要的区别是 JPQL 在您的实体上工作,并期望所有标识符对应于用于您的类和属性的名称。例如,如果 Name 列(第一个字母大写)映射到名为 name(小写)的属性,那么在 JPQL 查询中您应该使用 name(小写)。实体类名称和相应的表名称相同。 JPQL 还内置了对多对多关系的连接表的支持,JPQL 查询你想要什么

SELECT a
FROM B b JOIN b.aCollection a
WHERE b.name='ABC'

无需指定 JPA 从类上的注释中知道的所有连接条件。

@SecondaryTable 在这里不相关,它用于将单个实体拆分为多个表时使用。

【讨论】:

  • Eelke,谢谢你的信息,一切都很好,但我有一个愚蠢的疑问,我如何获取匹配的记录,比如如果我有 b.Name 如何获取 a.Name 和副-反之亦然。我在 em.CreateQuery 中尝试了上述 JOIN 条件,但这只会引发错误。
  • 很抱歉我搞砸了查询和这个很晚的反应。我已更正查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-26
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
相关资源
最近更新 更多