2014-04-08 92 views
0

我正在Grails工作& Groovy,但这是一个休眠问题。这里是我的Grails领域类:休眠条件子查询引用“根”查询的值

public Card { 
    // implicit Long id 
    String name 

    // ... and over a dozen other fields with various types. 
} 

我现在有这样的Hibernate查询:

def name = "foo" 

def result = session.createQuery("from Card as c where lower(c.name) like ? and c.id in (select max(c2.id) from Card as c2 where c.name = c2.name)") 
     .setString(0, "%${name}%") 
     .list() 

这得到所有卡包含字符串“foo”的名字,跳过上述除重复名称的任何卡“最新”(我假设更高的ID意味着'更新')。 我必须避免返回具有重复名称的卡片。

除了过滤名称和避免重复名称问题,我需要过滤和/或排序卡中的其他领域。我也需要分页。我想用Criteria API来做到这一点,因为生成SQL/HQL的方法会导致可维护性恶梦。

我只是不明白如何通过Criteria API来做这种查询。有分离的查询可以通过Criteria API用作子查询。然而,这些子查询似乎完全独立于主查询 - 我无法在'c.name'处将其与'c2.name'进行比较。

我在这里错过了什么?

回答

0

我自己想到了 - 通过Restrictions.sqlRestriction有一个Criterion允许自定义SQL在条件中使用。下面是等同的标准给我在这个问题HQL:

def name = 'foo' 

def crit = session.createCriteria(Card.class) 
def subcrit = DetachedCriteria.forClass(Card.class, 'c2') 

subcrit.add(Restrictions.sqlRestriction('this_.name = c2_.name')) 
subcrit.setProjection(Projections.max('id')) 

crit.add(Restrictions.ilike('name', "%${name}%")) 
    .add(Subqueries.propertyIn('id', subcrit)) 

def result = crit.list() 

有某种与别名分辨率sqlRestriction()的bug - 按说我可以用在表达{c2}.name,并有Hibernate来生成正确的SQL,但我发现我必须手动输出this_c2_以生成正确的SQL。

查看How to log SQL statements in Grails以查看如何记录生成的SQL并发现用于您自己的数据库的正确名称。

0

还有另一种可能,用从你的标准在你的子标准值(在我看来更多更清晰):

def name = 'foo' 

def crit = session.createCriteria(Card.class, 'c1') 
def subcrit = DetachedCriteria.forClass(Card.class, 'c2') 

subcrit.add(Restrictions.eqProperty('c1.name', 'c2.name')) 
subcrit.setProjection(Projections.max('c1.id')) 

crit.add(Restrictions.ilike('c1.name', "%${name}%")) 
    .add(Subqueries.propertyIn('c1.id', subcrit)) 

def result = crit.list() 

确保你把一个别名如c1为您的主要标准,并使用限制功能eqProperty()来比较这两个值。另外还有:Hibernate Java Doc