在Grails中,我试图找到一个具有一对多关系的精确条目的域类的实例。考虑这个例子:
class Author {
String name
List<Book> books
static hasMany = [books:Book]
}
class Book {
String title
static belongsTo = Author
}
我的数据库然后显示为:
author book
------------------------- ------------------------
| id | name | | id | title |
|----|------------------| ------------------------
| 1 | John Steinbeck | | 1 | Grapes of Wrath |
| 2 | Michael Crichton | | 2 | East of Eden |
------------------------- | 3 | Timeline |
| 4 | Jurassic Park |
------------------------
author_book
----------------------------------------
| author_books_id | book_id | book_idx |
----------------------------------------
| 1 | 1 | 0 | // John Steinbeck - Grapes of Wrath
| 1 | 2 | 1 | // John Steinbeck - East of Eden
| 2 | 3 | 0 | // Michael Crichton - Timeline
| 2 | 4 | 1 | // Michael Crichton - Jurassic Park
----------------------------------------
我希望能够在作者身上使用动态查找器。我正在搜索hasMany关系的完全匹配,以匹配此行为:
Author.findByBooks([1]) => null
Author.findByBooks([1, 2]) => author(id:1)
Author.findByBooks([1, 3]) => null
Author.findByBooks([3, 4]) => author(id:2)
尝试这会导致一个丑陋的Hibernate错误:
hibernate.util.JDBCExceptionReporter No value specified for parameter 1.
有没有人有动态查找器使用域类的hasMany关系?什么是获得理想行为的最“Grails-y”解决方案?
答案 0 :(得分:2)
如果Book
属于作者,则不清楚您的域模型。如果是这样,您应该将这一事实添加到您的域模型和查询,如Tom Metz所说。
让我做对了。您想要找到已经使用标题(或ID)写入书籍的作者,即“书籍1”和“书籍2”。 要进行检查工作,您必须两次加入Book表,以便将书籍标题从加入1与'Book 1'进行比较,将书籍标题从加入2与'Book2'进行比较。
可以假设以下测试应该有效:
void setUp() {
def author = new Author(name: "Ted Jones").save(flush: true)
def author2 = new Author(name: "Beth Peters").save(flush: true)
def author3 = new Author(name: "Foo Bar").save(flush: true)
def book1 = new Book(title: 'Book 1').save(flush: true)
def book2 = new Book(title: 'Book 2').save(flush: true)
def book3 = new Book(title: 'Book 3').save(flush: true)
def book4 = new Book(title: 'Book 4').save(flush: true)
author.addToBooks(book1)
author.addToBooks(book3)
author2.addToBooks(book2)
author2.addToBooks(book4)
author3.addToBooks(book1)
author3.addToBooks(book2)
}
void testAuthorCrit() {
def result = Author.withCriteria() {
books {
eq("title", "Book 1")
}
books {
eq("title", "Book 3")
}
}
assert 1 == result.size()
assertTrue(result.first().name == "Ted Jones")
}
但事实证明,结果集是空的。 Grails将每个书籍闭包中的语句合并为一个连接。
这是结果查询:
select this_.id as id1_1_, this_.version as version1_1_, this_.name as name1_1_, books3_.author_books_id as author1_1_, books_alia1_.id as book2_, books3_.books_idx as books3_, books_alia1_.id as id0_0_, books_alia1_.version as version0_0_, books_alia1_.title as title0_0_ from author this_ inner join author_book books3_ on this_.id=books3_.author_books_id inner join book books_alia1_ on books3_.book_id=books_alia1_.id where (books_alia1_.title=?) and (books_alia1_.title=?)
ASFAIK使用grails标准api无法实现这一目标。 但你可以改用hql。以下测试有效:
void testAuthorHql() {
def result = Author.executeQuery("select a from Author a join a.books bookOne join a.books bookTwo where bookOne.title=? and bookTwo.title=?", ['Book 1', 'Book 3'])
assert 1 == result.size()
assertTrue(result.first().name == "Ted Jones")
}
答案 1 :(得分:1)
我不是百分之百确定你真的可以让它工作(除非我在某处遗漏了一些文档)。但要获得所需,您需要使用标准:
class AuthorIntegrationTests {
@Before
void setUp() {
def author = new Author(name: "Ted Jones").save(flush: true)
def author2 = new Author(name: "Beth Peters").save(flush: true)
def book1 = new Book(title: 'Book 1').save(flush: true)
def book2 = new Book(title: 'Book 2').save(flush: true)
def book3 = new Book(title: 'Book 3').save(flush: true)
def book4 = new Book(title: 'Book 4').save(flush: true)
author.addToBooks(book1)
author.addToBooks(book3)
author2.addToBooks(book2)
author2.addToBooks(book4)
}
@After
void tearDown() {
}
@Test
void testAuthorCrit() {
def result = Author.withCriteria(uniqueResult: true) {
books {
inList("id", [1.toLong(), 3.toLong()])
}
}
assertTrue(result.name == "Ted Jones")
}
}
答案 2 :(得分:0)
您需要为域对象添加双向一对多关系。进入你的书域添加:
static belongsTo = [ author:Author ]
然后您可以查询:
Author a = Book.author