Hibernate Grails条件:id不在hasMany列表中
我要查找当前用户的所有未查看邮件 消息可供多个用户查看,因此使用布尔值指示消息是否已被查看是行不通的。因此,邮件中有一个被查看者列表 简化的域类如下所示:Hibernate Grails条件:id不在hasMany列表中,hibernate,grails,gorm,criteria,hibernate-criteria,Hibernate,Grails,Gorm,Criteria,Hibernate Criteria,我要查找当前用户的所有未查看邮件 消息可供多个用户查看,因此使用布尔值指示消息是否已被查看是行不通的。因此,邮件中有一个被查看者列表 简化的域类如下所示: class Message { static hasMany = [ viewees: User ] String content } class User { String name } 查找用户已查看的邮件非常简单: Message.withCriteri
class Message {
static hasMany = [ viewees: User ]
String content
}
class User {
String name
}
查找用户已查看的邮件非常简单:
Message.withCriteria {
viewees {
idEq(currentUser.id)
}
}
因此,要查找用户未查看的消息,我想我可以添加一个而不是{}
,如下所示:
Message.withCriteria {
viewees {
not {
idEq(currentUser.id)
}
}
}
但这将返回所有具有非当前用户的查看者的消息。这意味着它将返回另一个用户在查看列表中的消息,而不管当前用户是否在查看列表中
此外,如果有多个查看者,则返回同一消息的多个实例
标准生成器在列表中也有:
not {
inList( propertyName, list )
}
但我需要的是相反的结果。比如:
not {
inList( currentUser.id, 'viewees' )
}
但这并不受支持
有这样的东西我可以用吗?还是有别的办法?也许会以某种方式更改域模型?您可以使用HQL来获得所需的内容。下面是一个简单的查询:
class UserDomain {
String name
static List<MyMessage> findUnseenMessagesForUser(UserDomain user) {
MyMessage.executeQuery(
'select m from MyMessage m where :user not in elements(m.views)',
[user: user]
)
}
}
我建议通过创建一个额外的域类(如下所示)来显式地建模已读/未读信息:
如果用户
收到一条新消息,它将以未读状态添加到用户消息
,当用户
读取消息时,您将状态更改为已读
。现在,您可以轻松地检查单个用户接收的消息的状态
这样做的好处是,您不需要将特定于用户的信息添加到消息中。我不认为跟踪谁将消息视为消息的责任(当然它取决于您的业务域中的<代码>消息< /代码>的含义)。p>
如果您有更多与消息相关的特定于用户的信息,例如删除的标志(不再为该用户显示)或带星号的标志(我想保留它),那么这个额外的类也很有用。查询性能不太好的一种方法是message.all.findAll{!(其中的currentUser.id.viewees*.id)}
。这是执行查询的最坏情况。工作完美!非常感谢。我总是能够用Criteria Builder解决我的查询,所以我对HQL不是很熟悉。然而,在阅读了@Martin Hauner的答案后,我意识到这更适合我的业务领域。我同意你的观点,并意识到我需要更多关于这条消息的信息,如星号、喜欢、书签。。谢谢
void "test something"() {
setup:
def m1 = new MyMessage(content: "message 1")
def m2 = new MyMessage(content: "message 2")
def m3 = new MyMessage(content: "message 3").save(flush: true)
def u1 = new UserDomain(name: "user1").save(flush: true)
def u2 = new UserDomain(name: "user2").save(flush: true)
def u3 = new UserDomain(name: "user3").save(flush: true)
def u4 = new UserDomain(name: "user4").save(flush: true)
when:
m1.addToViews u1
m2.addToViews u1
m2.addToViews u3
m2.addToViews u4
m1.save(flush: true)
m2.save(flush: true)
then:
UserDomain.findUnseenMessagesForUser (u2). containsAll ([m1, m2, m3])
UserDomain.findUnseenMessagesForUser(u1).containsAll([m3])
}
class UserMessage {
enum State = {READ, UNREAD}
State state = State.UNREAD
Message message
User user
}