是否可以获得 Hibernate sqlRestriction 的连接表的 SQL 别名?
Posted
技术标签:
【中文标题】是否可以获得 Hibernate sqlRestriction 的连接表的 SQL 别名?【英文标题】:Is it possible to get the SQL alias of a join table for a Hibernate sqlRestriction? 【发布时间】:2011-01-21 16:07:25 【问题描述】:我有一个 Person 类,它有一个 String 别名集合,表示该人可能经过的其他名称。例如,克拉克肯特可能有别名“超人”和“钢铁侠”。德怀特霍华德还有一个别名“超人”。
@Entity
class Person
@CollectionOfElements(fetch=FetchType.EAGER)
Set<String> aliases = new TreeSet<String>();
Hibernate 在我的数据库中创建两个表,Person 和 Person_aliases。 Person_aliases 是一个包含列 Person_id 和元素的连接表。假设 Person_aliases 有以下数据
--------------------------------
| Person_id | element |
--------------------------------
| Clark Kent | Superman |
| Clark Kent | Man of Steel |
| Dwight Howard | Superman |
| Bruce Wayne | Batman |
--------------------------------
我想对所有别名为“超人”的人进行休眠条件查询。
由于此处列出的原因太长,我真的很想将其设为 Criteria 查询,而不是 HQL 查询(除非可以在 Criteria 对象上添加 HQL 限制,在这种情况下我会全力以赴)或原始 SQL 查询。因为根据How do I query for objects with a value in a String collection using Hibernate Criteria?,不可能使用 CriteriaAPI 引用值类型集合的元素,所以我想我会在我的条件对象上添加一个 SqlRestriction。
Criteria crit = session.createCriteria(Person.class);
crit.add(Restrictions.sqlRestriction("XXXXX.element='superman'");
希望 Hibernate 会创建类似的 SQL 语句
select *
from
Person this_
left outer join
Person_aliases aliases2_
on this_.id=aliases2_.Person_id
where
XXXXX.element='superman'
但是,我需要在 SQL 查询中使用 Person_aliases 表的表别名填写 XXXXX,在本例中为“aliases2_”。我注意到如果我需要对 Person 表别名的引用,我可以使用 alias。但这不起作用,因为 Person 是此 Criteria 的主表,而不是 Person_aliases。
我应该为 XXXXX 填写什么?如果没有像 alias 这样好的替代令牌,那么有没有办法让我休眠告诉我该别名将是什么?我注意到一个名为 generateAlias() org.hibernate.util.StringHelper 类的方法。这会帮助我预测别名是什么吗?
我真的非常想避免硬编码“aliases2_”。
感谢您的宝贵时间!
【问题讨论】:
【参考方案1】:正如 xmedeko 所暗示的,当你想做的时候:
crit.add(Restrictions.sqlRestriction(
"alias.joinedEntity.property='something'"));
你需要这样做:
crit.createCriteria("joinedEntity").add(Restrictions.sqlRestriction(
"alias.property='something'"));
这已经为我解决了类似的问题,而无需使用 HQL
【讨论】:
我应该使用实际字符串alias
还是将其替换为像 accountUser
这样的对象名称?
使用字符串 alias 它是一个休眠关键字,不幸的是它是在标准世界中使用别名的唯一方法。
这工作正常,但我找不到与此相关的文档。你认识一个吗?
docs.jboss.org/hibernate/orm/3.5/reference/en/html/… - 取决于你的版本。
@pstanton 如果我有另一个别名怎么办?他叫什么名字【参考方案2】:
Criteria API 似乎不允许查询元素集合,请参阅HHH-869(仍然开放)。所以要么尝试建议的解决方法 - 我没有 - 要么切换到 HQL。以下 HQL 查询将起作用:
from Person p where :alias in elements(p.aliases)
【讨论】:
感谢您的回复 - 由于之前的 Stack Overflow 问题,我确实知道不幸的 Criteria API 限制,但希望通过 sqlRestriction 使用本机 SQL sn-p 可能会提供一个“hack”会让我们仍然使用标准。但是我想不出一种方法来获取对连接表名称的引用。如果没有办法,我会像你建议的那样求助于 HQL。但是,我不希望这会占用比我在这里解释的更多空间的原因(这个问题是我们实际查询的简化表示) @Jason 也许有可能,但 我 不知道如果不对表名进行硬编码。【参考方案3】:尝试创建另一个标准,例如
Criteria crit = session.createCriteria(Person.class, "person");
Criteria subC = crit.createCriteria("Person_aliases", "Person_aliases");
subC.add(Restrictions.sqlRestriction("alias.element='superman'");
【讨论】:
【参考方案4】:this link 可以帮助你吗?它建议:
List persons = sess.createCriteria(Person.class)
.createCriteria("company")
.add(Restrictions.sqlRestriction("companyName || name like (?)", "%Fritz%", Hibernate.STRING))
.list();
【讨论】:
在主类上调用 createCriteria() 方法来连接对象解决了我的问题。我在连接对象类的子条件中添加了所有连接字段,我的问题就解决了。【参考方案5】:查看这个 Hibernate 错误并使用附件:
https://hibernate.atlassian.net/browse/HHH-2952 https://hibernate.atlassian.net/browse/HHH-2381【讨论】:
【参考方案6】:这个问题实际上已经很老了,但是由于我今天遇到了同样的问题并且没有答案满足我的需求,所以我根据 Brett Meyer 在HHH-6353 上的comment 提出了以下解决方案,即这个问题不会被修复。
基本上,我扩展了SQLCriterion 类,使其能够处理的不仅仅是基表别名。为方便起见,我编写了一个小型容器类,将用户给定的别名与匹配的子条件实例链接起来,以便能够用为子条件创建的别名 hibernate 替换用户给定的别名。
这里是MultipleAliasSQLCriterion类的代码
public class MultipleAliasSQLCriterion extends SQLCriterion
/**
* Convenience container class to pack the info necessary to replace the alias generated at construction time
* with the alias generated by hibernate
*/
public static final class SubCriteriaAliasContainer
/** The alias assigned at construction time */
private String alias;
/** The criteria constructed with the specified alias */
private Criteria subCriteria;
/**
* @param aAlias
* - the alias assigned by criteria construction time
* @param aSubCriteria
* - the criteria
*/
public SubCriteriaAliasContainer(final String aAlias, final Criteria aSubCriteria)
this.alias = aAlias;
this.subCriteria = aSubCriteria;
/**
* @return String - the alias
*/
public String getAlias()
return this.alias;
/**
* @return Criteria - the criteria
*/
public Criteria getSubCriteria()
return this.subCriteria;
private final SubCriteriaAliasContainer[] subCriteriaAliases;
/**
* This method constructs a new native SQL restriction with support for multiple aliases
*
* @param sql
* - the native SQL restriction
* @param aSubCriteriaAliases
* - the aliases
*/
public MultipleAliasSQLCriterion(final String sql, final SubCriteriaAliasContainer... aSubCriteriaAliases)
super(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
this.subCriteriaAliases = aSubCriteriaAliases;
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException
// First replace the alias of the base table alias
String sql = super.toSqlString(criteria, criteriaQuery);
if (!ArrayUtils.isEmpty(this.subCriteriaAliases))
for (final SubCriteriaAliasContainer subCriteriaAlias : this.subCriteriaAliases)
sql = StringHelper.replace(sql, subCriteriaAlias.getAlias(), criteriaQuery.getSQLAlias(subCriteriaAlias.getSubCriteria()));
return sql;
我是这样用的
final String sqlRestriction = "...";
final String bankAccountAlias = "ba";
final Criteria bankAccountCriteria = customerCriteria.createCriteria("bankAccount", bankAccountAlias);
SubCriteriaAliasContainer bankAccountSubAliasCon = new SubCriteriaAliasContainer(bankAccountAlias, bankAccountCriteria);
customerCriteria.add(new MultipleAliasSQLCriterion(sqlRestriction, bankAccountSubAliasCon));
但不需要在创建条件时指定别名 - 您也可以在 SQL 限制中指定别名并将其传递给容器。
final String sqlRestriction = "... VALUES(ba.status_date), (ba.account_number) ...";
final Criteria bankAccountCriteria = customerCriteria.createCriteria("bankAccount");
SubCriteriaAliasContainer bankAccountSubAliasCon = new SubCriteriaAliasContainer("ba", bankAccountCriteria);
customerCriteria.add(new MultipleAliasSQLCriterion(sqlRestriction, bankAccountSubAliasCon));
【讨论】:
谢谢,这很有帮助! 我想知道您的示例中是否没有两个拼写错误。 bankAccountSubAliasCon 对象不应该传递给 MultipleAliasSQLCriterion 构造函数吗? 这是我使用你的实用程序的方式:` String hibernatePersonAlias = "p";条件 personCriteria = mainCriteria.createCriteria("person", hibernatePersonAlias);字符串 personSalarySqlCriterion = hibernatePersonAlias + ".salary > 1500"; MultipleAliasSQLCriterion.SubCriteriaAliasContainer personAliasContainer = new MultipleAliasSQLCriterion.SubCriteriaAliasContainer(hibernatePersonAlias, personCriteria); mainCriteria.add(new MultipleAliasSQLCriterion(personSalarySqlCriterion, personAliasContainer));` 是的,我想你可能是对的@Stephane。我将对其进行编辑以表示正确使用 嗨 Marius,我尝试做一个类似的实用程序***.com/questions/36172803/…,但它没有按预期工作。知道您可能对此有更好的理解,如果您有时间看一下,我会联系您。谢谢!【参考方案7】:org.hibernate.criterion.CriteriaQuery
有一个方法 getColumnsUsingProjection
,它为您提供别名列名。
您可以实现自己的Criterion
,以org.hibernate.criterion.PropertyExpression
为例。
【讨论】:
【参考方案8】:public class Products
private Brands brand;
...
public class Brands
private long id;
...
...
DetachedCriteria dc=DetachedCriteria.forClass(Products.class, "prod");
dc.add(Restrictions.ge("prod.brand.id", Long.parseLong("12345")));
【讨论】:
以上是关于是否可以获得 Hibernate sqlRestriction 的连接表的 SQL 别名?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以获得 Hibernate sqlRestriction 的连接表的 SQL 别名?
基础 - 解决 Hibernate / JDBC 连接池问题
配置NHibernate hibernate.cfg.xml文件以获得更多连接字符串