Как избежать дублирования записей в NHibernate

Я пытаюсь хранить сообщения, которые я получаю, в базе данных с помощью NHibernate. Однако существует вероятность того, что одно и то же сообщение будет получено дважды, и в этом случае я не хочу сохранять дубликат в базе данных. Первой моей мыслью было сделать следующее:

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

var newMessages = messages.Except(alreadyStoredMessages);

Однако похоже, что NHibernate не поддерживает Intersect, поэтому это приведет к исключению. Я знаю, что всегда могу получить все сообщения, преобразовать их в список или массив, а затем выполнить пересечение, но это будет не очень эффективно.

Класс Message реализует IEquatable, а также переопределяет GetHashCode() и Equals(object obj). Равенство зависит от нескольких свойств (отметка времени, несколько строк и т. д.).


person Henry H    schedule 19.10.2012    source источник


Ответы (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();
    }
}
person Firo    schedule 19.10.2012
comment
Разве вы не должны проверить, заполнена ли ваша очередь перед удалением из очереди? - person Cole W; 19.10.2012
comment
Фильтрация кажется правдоподобным решением. Однако у меня проблема с поиском метода «In». - person Henry H; 19.10.2012
comment
В итоге я использовал IsInG(messages.Select(m => m.TimeStamp)).List() вместо In(messages.Select(m => m.timeStamp)).AsEnumerable(), и, кажется, все работает нормально. - person Henry H; 19.10.2012