我正在处理的域名中存在以下关联(不幸的是,实际上并不是盗版者)。一艘船上有很多海盗。我希望能够找到所有有船长的船只,船上没有任何陆地润滑油。
class Pirate {
String name
Rank rank
enum Rank {
CAPTAIN,
DECK_HAND,
LAND_LUBBER
}
}
class Ship {
static hasmany = [crew:Pirate]
}
我正在尝试使用Hibernate标准,因为从长远来看,我希望这是一个可以与其他查询链接的命名查询。这是我正在使用的标准。
def pirateShips = Ship.withCriteria {
crew {
eq('rank', Pirate.Rank.CAPTAIN)
not {
eq('rank', Pirate.Rank.LAND_LUBBER)
}
}
}
当我创建以下实体时,我没有得到预期的结果。
def blackbeard = new Pirate(name:'Blackbeard', rank:Pirate.Rank.CAPTAIN).save()
def deckHand = new Pirate(name:'Deck Hand', rank:Pirate.Rank.DECK_HAND).save()
def landLubber = new Pirate(name:'Land Lubber', rank:Pirate.Rank.LAND_LUBBER).save()
def ship = new Ship(name:'Ship 1', crew:[blackbeard]).save()
def infiltrator = new Ship(name:'Ship 2', crew:[blackbeard, landLubber]).save()
def normalShip = new Ship(name:'Ship 3', crew:[blackbeard, deckHand]).save(flush:true)
运行前面提到的查询导致返回所有3艘船只,而我预计只返回第1船和第3船(第2船有一块令人讨厌的土地润滑剂,对我来说没用)。
有没有办法使用条件API生成此类查询?如果不是,我将如何在HQL中编写查询?
答案 0 :(得分:3)
您的查询无法正常工作的原因主要是因为SQL连接的性质。如果任何单独的行符合您的条件,它将返回一艘船。在连接中有行是船长但不是陆地润滑剂(即每个黑胡子行),所以你得到了所有船只。这样写的标准就是不是所有的机组人员,而是每个机组成员都是单独的。
有几种不同的方法可以解决这个问题。一种是使用子选择查询。有可能在标准中写这个,但我不熟悉它们,因为我更喜欢HQL,因为它看起来更像SQL,我很满意。
这是一个示例HQL查询,它返回预期的第1和第3船:
def blackbeard = Pirate.buildLazy(name: 'Blackbeard', rank: Pirate.Rank.CAPTAIN)
def deckHand = Pirate.buildLazy(name: 'Deck Hand', rank: Pirate.Rank.DECK_HAND)
def landLubber = Pirate.buildLazy(name: 'Land Lubber', rank: Pirate.Rank.LAND_LUBBER)
def ship = Ship.buildLazy(name: 'Ship 1').with { crew = [blackbeard] }
def infiltrator = Ship.buildLazy(name: 'Ship 2').with { crew = [blackbeard, landLubber] }
def normalShip = Ship.buildLazy(name: 'Ship 3').with { crew = [blackbeard, deckHand] }
def pirateShips = Ship.executeQuery( """
select s from Ship s
join s.crew as p
where p.rank = :captain
and s not in
(select s1 from Ship s1
join s1.crew as p1
where p1.rank = :landLubber)
""",
[captain: Pirate.Rank.CAPTAIN, landLubber: Pirate.Rank.LAND_LUBBER] )
assert( ["Ship 1", "Ship 3"] == pirateShips.name.sort() )
(我还使用了构建测试数据插件来延迟构建实例,而不是新建它们,因为它使脚本更容易运行多次而无需一直重新启动grails控制台。)
在这个查询中,我找到了所有带船长的船只,并从那套船上拆除了所有有陆地润滑油的船只。
答案 1 :(得分:0)
我认为您必须使用HQL,但我确实遇到了以下文章,可能会让您对如何解决问题有所了解。
http://adhockery.blogspot.com/2009/04/associations-and-criteria-queries.html