LINQ To SQL игнорировать исключение уникального ограничения и продолжить - PullRequest
5 голосов
/ 18 марта 2010

У меня есть одна таблица в базе данных с именем Users

Users
------
ID (PK, Identity)
Username (Unique Index)

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

Что я хочу сделать, это просто вставить нового пользователя и проигнорировать исключение, если ограничение уникального ключа нарушено (поскольку в данном случае это явно дублирующая запись). Это сделано для того, чтобы избежать необходимости создавать там, где не существует вид запросов.

Во-первых, это будет более эффективным или вместо этого мой код вставки будет проверять наличие дубликатов? Я больше обращаюсь к базе данных с такой логикой, поскольку это предотвращает вставку дублирующихся данных любым другим типом клиентов.

Моя другая проблема связана с LINQ To SQL. У меня есть следующий код:

public class TestRepo
{
    DatabaseDataContext database = new DatabaseDataContext();

    public void Add(string username)
    {
        database.Users.InsertOnSubmit(new User() { Username = username });
    }

    public void Save()
    {
        database.SubmitChanges();
    }
}

А затем я перебираю коллекцию и вставляю новых пользователей, игнорируя любые исключения:

TestRepo repo = new TestRepo();

foreach (var name in new string[] { "Tim", "Bob", "John" })
{
    try
    {
        repo.Add(name);
        repo.Save();
    }
    catch {  }
}

При первом запуске, отлично, у меня в таблице три пользователя. Если я удаляю второй и снова запускаю этот код, ничего не вставляется. Я ожидал, что первая вставка потерпит неудачу с исключением, вторая будет успешной (так как я только что удалил этот элемент из БД), а третья - неудачной.

То, что, похоже, происходит, заключается в том, что после создания исключения SqlException (даже если цикл продолжает повторяться) все последующие операции вставки завершаются неудачно - даже когда в таблице нет строки, которая могла бы вызвать уникальное нарушение.

Может кто-нибудь объяснить это?

P.S. Единственный обходной путь, который я смог найти, состоял в том, чтобы создавать экземпляр репо каждый раз перед вставкой, затем он работал точно так же, как и предполагалось, что указывает на то, что это как-то связано с LINQ To SQL DataContext.

Спасибо.

Ответы [ 4 ]

1 голос
/ 19 марта 2010

При второй вставке dataContext снова попытается вставить первые объекты, поскольку он находится в карте идентификаторов для этого dataContext (ваше желание вставить 'Tim' все еще ожидает выполнения - после первого захвата).

В первом цикле вы вставляете "Тим" Во втором "Тим" и "Боб" В третьем «Тим», «Боб» и «Джон» Таким образом, вы не вставляете только «Bob» во второй цикл, и именно поэтому не удается.

Вы можете попытаться удалить ошибочное имя из DataContext в кэше, но в любом случае многократные отправки в одном контексте данных - очень плохая идея (я сгорел от этого).

0 голосов
/ 14 апреля 2010

Трудно сказать, является ли ваш метод "более эффективным". Это будет зависеть от того, как часто вы получаете дубликаты аккаунтов. Если у вас очень высокая скорость, вы теряете скорость, так как, скорее всего, потребуется больше времени для обработки исключения, чем для проверки существования записи.

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

0 голосов
/ 18 марта 2010

Вы должны проверить существование, используя хитрость try catch.

foreach (var name in new string[] { "Tim", "Bob", "John" })
{
    var u = from users in db.Users
            where users.username == name
            select users;

    if (u.Count() == 0)
    {
       User user = new User();
       user.name = name;
       db.Users.InsertOnSubmit(user);
       db.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
    }
}
0 голосов
/ 18 марта 2010

Попробуйте вызвать DataContext.Refresh в вашем DataContext между тестовыми прогонами.

Я думаю, что вы зациклены на внутреннем кэшировании в Linq-to-Sql, поэтому пересоздание DataContext действует как обходной путь: когда вы создаете новый DataContext, кэш нового объекта будет пустым.

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