gpt4 book ai didi

hibernate - 将具有 InheritanceType.JOINED 的实体添加到 native 查询

转载 作者:行者123 更新时间:2023-12-04 01:12:26 25 4
gpt4 key购买 nike

我正在努力让原生查询与 InheritanceType.JOINED 一起使用.来自 hibernate documentation我已经找到:

13.1.6. Handling inheritance

Native SQL queries which query for entities that are mapped as part of an inheritance must include all properties for the baseclass and all its subclasses.



使用以下两个实体:

@Data
@Entity
@Table(name = "my_super")
@EqualsAndHashCode(of = {"id"})
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class MySuper {

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;

}

和:

@Data
@Entity
@Table(name = "my_sub_a")
@EqualsAndHashCode(callSuper = true)
public class MySubA extends MySuper {

@Column(name = "x")
private int x;

}

当我尝试使用以下方法创建 native 查询时:

Object actual = session
.createNativeQuery("SELECT {s.*} FROM my_super {s} LEFT JOIN my_sub_a {a} USING (id)")
.addEntity("s", MySuper.class)
.getSingleResult();

它转换为查询:
SELECT s.id as id1_1_0_, s_1_.x as x1_0_0_, case when s_1_.id is not null then 1 when s.id is not null then 0 end as clazz_0_ FROM my_super s LEFT JOIN my_sub_a  a  USING (id) 

然后失败:
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement
Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement
Caused by: org.h2.jdbc.JdbcSQLException: Column "S_1_.X" not found; SQL statement:

所以我们观察到别名注入(inject)的工作,发现它可能需要 x my_sub_a 的栏目也是。然而,它无法找出 my_sub_a 的别名。 .应该如何修改我的代码以使该别名也正确连接?

我的代码位于 https://gist.github.com/JWGmeligMeyling/51e8a305f3c268eda473511e202f76e8为了方便重现我的问题。

(我知道这个查询也可以很容易地用 JPQL 或 HQL 表示,甚至可以使用 EntityManagerSession API 来实现。但是我确实想在更复杂的查询中使用它,我简化了此问题所需的所有详细信息)。

最佳答案

这个问题似乎与使用的底层数据库方言有关,换句话说,与一些“异国情调”的查询部分有关。您所描述的行为可以通过您提供的查询进行复制,但有一些微小的 tweeks 运行时不会出现错误 - 取决于您要使用的方言。

在您的示例中,您使用 H2 数据库,但我认为这不是您的生产方言,对吧?我还尝试使用 PostgresSQL 数据库(在 9.5 版中)。

使用源查询,在 H2 和 PostgreSQL 上的行为是相同的。但是,如果您从列和别名中删除花括号(看起来像一些 ODBC escape sequences )并更改 USING clause到明确的 ON a.id = s.id条件查询是可执行的,没有任何异常(exception)。

为了验证行为,我使用 Hibernate Session 或 EntityManager 创建了一些具有不同查询的测试,因为在查看了您链接的示例代码后,我对 Hibernate Session interface 的混合使用感到困惑。和 EntityManager methods like createNativeQuery .如有疑问,我尝试了两者。
我使用了相同的实体和或多或少相同的配置和测试代码,就像您在示例中所做的那样,但在 Spring Boot environment 中, 只是为了方便。在我使用的数据库之间切换 Spring Boot Profiles ,只需激活/取消注释 @ActiveProfiles("postgres")如果您有两个数据库的配置,则部分。

以下是测试,希望对您有所帮助:

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.Session;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
//@ActiveProfiles("postgres") // activate for PostgreSQL tests
public class InheritanceDemoApplicationTests {

private static final String QUERY = "SELECT {s.*} FROM my_super {s} LEFT JOIN my_sub_a {a} USING (id)";
private static final String QUERY_WITHOUT_ODBC_ESCAPES = "SELECT s.* FROM my_super s LEFT JOIN my_sub_a a USING (id)";
private static final String QUERY_WITHOUT_USING_KEYWORD = "SELECT {s.*} FROM my_super {s} LEFT JOIN my_sub_a {a} ON a.id = s.id";
private static final String QUERY_WITHOUT_ODBC_ESCAPES_AND_WITHOUT_USING_KEYWORD = "SELECT s.* FROM my_super s LEFT JOIN my_sub_a a ON a.id = s.id";

@PersistenceContext
private EntityManager entityManager;

@Test
public void sessionQuery() {
validateQueryViaSession(QUERY);
}

@Test
public void entityManagerQuery() {
validateQueryViaEntityManager(QUERY);
}

@Test // works for PostgreSQL
public void sessionQueryWithoutOdbc() {
validateQueryViaSession(QUERY_WITHOUT_ODBC_ESCAPES);
}

@Test // works for PostgreSQL
public void entityManagerQueryWithoutOdbc() {
validateQueryViaEntityManager(QUERY_WITHOUT_ODBC_ESCAPES);
}

@Test
public void sessionQueryWithoutUsing() {
validateQueryViaSession(QUERY_WITHOUT_USING_KEYWORD);
}

@Test // works for H2
public void entityManagerQueryWithoutUsing() {
validateQueryViaEntityManager(QUERY_WITHOUT_USING_KEYWORD);
}

@Test // works for H2 & PostgreSQL
public void sessionQueryWithoutOdbcAndWithoutUsing() {
validateQueryViaSession(QUERY_WITHOUT_ODBC_ESCAPES_AND_WITHOUT_USING_KEYWORD);
}

@Test // works for H2 & PostgreSQL
public void entityManagerQueryWithoutOdbcAndWithoutUsing() {
validateQueryViaEntityManager(QUERY_WITHOUT_ODBC_ESCAPES_AND_WITHOUT_USING_KEYWORD);
}

@SuppressWarnings("rawtypes")
private void validateQueryViaSession(final String queryString) {
final MySubA match = persistMySubA();
List result = entityManager.unwrap(Session.class).createSQLQuery(queryString).addEntity("s", MySuper.class)
.list();
assertThat(result.iterator().next()).isEqualToComparingFieldByField(match);
}

@SuppressWarnings("rawtypes")
private void validateQueryViaEntityManager(final String queryString) {
final MySubA match = persistMySubA();
List result = entityManager.createNativeQuery(queryString, MySuper.class).getResultList();
assertThat(result.iterator().next()).isEqualToComparingFieldByField(match);
}

private MySubA persistMySubA() {
final MySubA mySubA = new MySubA();
mySubA.setX(1);
entityManager.persist(mySubA);
entityManager.flush();
return mySubA;
}

}

关于hibernate - 将具有 InheritanceType.JOINED 的实体添加到 native 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39359924/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com