我有一个Person类,它有一个别名的String集合,表示人可能经过的其他名称。例如,克拉克肯特可能有别名“超人”和“钢铁侠”。德怀特霍华德也有别名“超人”。
@Entity
class Person {
@CollectionOfElements(fetch=FetchType.EAGER)
Set<String> aliases = new TreeSet<String>();
Hibernate在我的数据库中创建了两个表,Person和Person_aliases。 Person_aliases是一个包含Person_id和element列的连接表。假设Person_aliases具有以下数据
--------------------------------
| Person_id | element |
--------------------------------
| Clark Kent | Superman |
| Clark Kent | Man of Steel |
| Dwight Howard | Superman |
| Bruce Wayne | Batman |
--------------------------------
我想为所有使用“超人”别名的人制作一个hibernate Criteria查询。
由于这里列出的原因太长了,我真的想把它作为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}这样的好的替代令牌,那么我有没有办法让hibernate告诉我该别名会是什么?我注意到一个名为generateAlias()org.hibernate.util.StringHelper类的方法。这有助于我预测别名会是什么吗?
我真的非常想避免硬编码'aliases2_'。
谢谢你的时间!
答案 0 :(得分:9)
正如xmedeko所暗示的,当你想要做的时候:
crit.add(Restrictions.sqlRestriction(
"{alias}.joinedEntity.property='something'"));
你需要改为:
crit.createCriteria("joinedEntity").add(Restrictions.sqlRestriction(
"{alias}.property='something'"));
这为我解决了类似的问题而没有使用HQL
答案 1 :(得分:4)
似乎Criteria API不允许查询元素集合,请参阅HHH-869(仍处于打开状态)。所以要么尝试建议的解决方法 - 我没有 - 或切换到HQL。以下HQL查询将起作用:
from Person p where :alias in elements(p.aliases)
答案 2 :(得分:3)
请参阅此Hibernate错误并使用附加文件:
答案 3 :(得分:3)
尝试创建另一个标准,如
Criteria crit = session.createCriteria(Person.class, "person");
Criteria subC = crit.createCriteria("Person_aliases", "Person_aliases");
subC.add(Restrictions.sqlRestriction("{alias}.element='superman'");
答案 4 :(得分:2)
五月this link可以帮到你吗?它建议:
List persons = sess.createCriteria(Person.class)
.createCriteria("company")
.add(Restrictions.sqlRestriction("companyName || name like (?)", "%Fritz%", Hibernate.STRING))
.list();
答案 5 :(得分:1)
这个问题实际上很老了,但是因为我今天遇到了同样的问题并且没有答案满足我的需求,我提出了以下解决方案,基于comment的Brett Meyer HHH-6353 ,这个问题不会得到解决。
基本上,我扩展了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));
答案 6 :(得分:0)
org.hibernate.criterion.CriteriaQuery
有一个方法getColumnsUsingProjection
,它为您提供别名列名。
您可以使用Criterion
作为示例来实现自己的org.hibernate.criterion.PropertyExpression
。
答案 7 :(得分:-4)
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")));