2012-10-19 126 views
0

我想存储使用NHibernate在数据库中接收到的消息。但是,有可能会收到两次相同的消息,在这种情况下,我不想将副本保存到数据库中。我的第一个想法是做到以下几点:在NHibernate中避免重复的条目

// in SaveRange(IEnumerable<Message> messages 
var alreadyStoredMessages = session.Query<Message>().Intersect(messages); 

var newMessages = messages.Except(alreadyStoredMessages); 

但是,似乎NHibernate不支持相交,所以这将导致一个异常。我知道我总是可以获取所有消息,将它们转换为列表或数组,然后执行相交,但这不会非常有效。

Message类实现了IEquatable,它也覆盖了GetHashCode()和Equals(object obj)。平等取决于几个属性(时间戳,几个字符串等)。

回答

1

如果所有新邮件马上来使用过滤器:

var alreadyStoredMessages = session.QueryOver<Message>() 
    .WhereRestrictionOn(m => m.timestamp).In(messages.Select(m => m.timeStamp)) 
    .AsEnumerable() 
    .Intersect(messages); 

var newMessages = messages.Except(alreadyStoredMessages).ToList(); 

假设重复消息后,之后彼此很近:保持最后n的缓冲区接收到的消息,并期待放进去。

var lastMessages = new Queue<Message>(100); 
while(true) 
{ 
    var message = GetNextMessage(); 
    if (!lastMessages.Contains(message)) 
    { 
     lastMessages.Enqueue(message); 
     session.Save(message); 
     if (lastMessages.Count >= 100); 
      lastMessages.Dequeue(); 
    } 
} 
+0

难道你不应该检查一下,以确保你的队列在离队之前是“满的”吗? –

+0

过滤似乎是一个合理的解决方案。虽然我找到'In'方法有问题。 –

+0

我最终使用'IsInG(messages.Select(m => m.TimeStamp))。List()'而不是'In(messages.Select(m => m.timeStamp))。AsEnumerable()'工作得很好。 –