Дубликат записи создан, но почему? (Линк к sql) - PullRequest
3 голосов
/ 25 февраля 2011

У нас есть таблица, в которой хранятся подписки на новостную рассылку (ID, EmailAddress, MyNewsletter1 и т. Д.), И когда мы сохраняем подписку, мы сначала проверяем, есть ли уже настроенная подписка для этого адреса электронной почты. Если есть, мы обновляем эту запись, если нет, мы вставляем новую. Каким-то образом туда проник тайный адрес электронной почты, и я не знаю, как. Первичный ключ - это ID, поэтому мы можем изменить его на EmailAddress, но мне все еще интересно, как это произошло. Может ли это быть проблемой параллелизма? Это код:

public static void SaveSubscription(NewsletterSubscription subscription)
{
    using (MyDataContext db = new MyDataContext())
    {
        // does this email already have subscriptions?
        NewsletterSubscription result = db.NewsletterSubscriptions.SingleOrDefault(r => r.Email == subscription.Email);

        if (result != null)
        {
            // update instead of creating new record
            result.MyNewsletter1 = subscription.MyNewsletter1;
            result.MyNewsletter2 = subscription.MyNewsletter2;
            result.MyNewsletter3 = subscription.MyNewsletter3;
            result.MyNewsletter4 = subscription.MyNewsletter4;
        }
        else
        {
            // create new subscription record
            subscription.RegisterDate = DateTime.Now;
            db.NewsletterSubscriptions.InsertOnSubmit(subscription);
        }

        db.SubmitChanges();
    }
}

Спасибо,

Annelie

Ответы [ 3 ]

2 голосов
/ 25 февраля 2011

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

using (var tran = new TransactionScope()) { 
    using (MyDataContext db = new MyDataContext()) {
        // ... your existing code here
    }
    tran.Complete();
}

Это вызывает блокировку диапазона клавиш во время выбора, поэтому любой второй поток, выполняющий чтение, будет заблокирован до завершения транзакции; поэтому вы не получите два SPID, которые видят «без строки», а затем пытаются выполнить вставку; вместо этого первый SPID будет блокировать второй на несколько критических миллисекунд, пока он выполняет свою работу; только когда первый SPID решил, следует ли (или нет) вставить данные (и вызвать Complete или выполнить откат), второй SPID узнает.

Также обратите внимание, что вам не нужно менять первичный ключ, чтобы сделать его уникальным - просто добавьте уникальное ограничение. Тогда вам не нужно ничего менять , ссылаясь на эту таблицу.

2 голосов
/ 25 февраля 2011

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

1 голос
/ 25 февраля 2011

Код выглядит нормально, так что я думаю, проблема с параллелизмом. Если в электронном письме в любом случае должна быть только одна запись, я бы предложил добавить / заменить ее на первичном ключе.

В этом случае SubmitChanges выдаст исключение, если вы попытаетесь вставить ту же запись снова. Затем вы можете выполнить измерение в блоке catch, чтобы обновить запись (или отменить ее, если это правильно), и продолжить выполнение.

Получите базу данных, которая поможет вам избежать дублирования, предоставляя правильные первичные ключи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...