我要查找当前用户所有未查看的消息。
消息可以供多个用户查看,因此使用布尔值来指示是否查看消息将不起作用。因此,消息有一个视图列表。
简化的域类如下:
class Message {
static hasMany = [ viewees: User ]
String content
}
class User {
String name
}
查找用户已查看的消息是微不足道的:
Message.withCriteria {
viewees {
idEq(currentUser.id)
}
}
所以要找到用户没有看过的消息,我想我可以添加一个not{ }
,像这样:
Message.withCriteria {
viewees {
not {
idEq(currentUser.id)
}
}
}
但是这将返回所有具有非当前用户的查看者的消息。这意味着它将返回另一个用户在查看列表中的消息,而不管当前用户是否在查看列表中。
除此之外,如果有多个视图,则返回同一消息的多个实例。
标准构建器也有inList
:
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]
)
}
}
/
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
}
如果User
接收到一个新的消息,它被添加到UserMessages
为未读,当User
读取消息时,您将状态更改为READ
。您现在可以很容易地检查单个用户收到的消息的状态。
这样做的好处是不需要向Message
添加特定于用户的信息。我不认为跟踪谁看到了消息是消息的责任(当然,这取决于Message
在您的业务领域中的含义)。
如果您有更多与消息相关的用户特定信息,这个额外的类也很有用,例如已删除的标志(不再为该用户显示它)或星号标志(我想保留它)。