ChangeConflictException в обновлении Linq до Sql

Я в мире боли с этим, и я очень благодарен, если кто-то может помочь.

У меня есть DataContext, связанный с одной тестовой таблицей в базе данных. Таблица тестов выглядит следующим образом:

CREATE TABLE [dbo].[LinqTests](
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [StringValue] [varchar](255) NOT NULL,
    [DateTimeValue] [datetime] NOT NULL,
    [BooleanValue] [bit] NOT NULL,
    CONSTRAINT [PK_LinqTests] PRIMARY KEY CLUSTERED ([ID] ASC))
ON [PRIMARY]

Используя Linq, я могу добавлять, извлекать и удалять строки из тестовой таблицы, но я не могу обновить строку - для UPDATE я всегда получаю исключение ChangeConflictException с пустой коллекцией ObjectChangeConflict.MemberConflicts. Вот код:

var dataContext = new UniversityDataContext();
dataContext.Log = Console.Out;

for (int i = 1; i <= 1; i++) {
    var linqTest = dataContext.LinqTests.Where(l => (l.ID == i)).FirstOrDefault();

    if (null != linqTest) {
        linqTest.StringValue += " I've been updated.";
    }
    else {
        linqTest = new LinqTest {
            BooleanValue = false,
            DateTimeValue = DateTime.UtcNow,
            StringValue = "I am in loop " + i + "."
        };
        dataContext.LinqTests.InsertOnSubmit(linqTest);
    }
}

try {
    dataContext.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException exception) {
    Console.WriteLine("Optimistic concurrency error.");
    Console.WriteLine(exception.Message);
    Console.ReadLine();
}

Console.ReadLine();

Вот результат журнала для обновления, выполняемого через DataContext.

UPDATE [dbo].[LinqTests]
SET [StringValue] = @p3
WHERE ([ID] = @p0) AND ([StringValue] = @p1) AND ([DateTimeValue] = @p2) AND (NOT ([BooleanValue] = 1))
-- @p0: Input BigInt (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input VarChar (Size = 15; Prec = 0; Scale = 0) [I am in loop 1.]
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [3/19/2009 7:54:26 PM]
-- @p3: Input VarChar (Size = 34; Prec = 0; Scale = 0) [I am in loop 1. I've been updated.]
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.30729.1

Я запускаю этот запрос на кластерном SQL Server 2000 (8.0.2039). Я не могу, для жизни, понять, что происходит здесь. Выполнение аналогичного запроса UPDATE к базе данных, похоже, отлично работает.

Заранее благодарим за помощь.

Ответ 1

Наконец я понял, что с этим происходит. По-видимому, для этого сервера была включена опция "no count" .

В Microsoft SQL Server Management Studio 2005:

  • Щелкните правой кнопкой мыши на сервере и нажмите Свойства
  • В левой части окна "Свойства сервера" выберите страницу Подключения
  • В разделе "Параметры подключения по умолчанию" убедитесь, что "no count" не выбран.

По-видимому, LINQ to SQL использует @@ROWCOUNT после обновлений для выпуска автоматической оптимизированной проверки concurrency. Конечно, если "no count" включен для всего сервера, @@ROWCOUNT всегда возвращает ноль, а LINQ to SQL генерирует исключение ConcurrencyException после выпуска обновлений базы данных.

Это не единственное поведение, которое использует LINQ to SQL. LINQ to SQL не выполняет автоматизированную оптимизацию concurrency с @@ROWCOUNT, если у вас есть столбец TIMESTAMP в вашей таблице.

Ответ 2

Возможно ли, что любая из данных для строки изменилась между тем, когда она была восстановлена, и было предпринято обновление? Поскольку LINQ- > SQL имеет автоматическую проверку concurrency, которая будет проверять содержимое объекта по отношению к текущим сохраненным значениям (как вы видите в сгенерированном запросе). Если возможно, что любое из полей изменилось для строки в БД и объект, который отслеживает LINQ, обновление не будет выполнено. Если это происходит и по уважительной причине, и вы знаете, какие поля, вы можете обновить объект в дизайнере DBML; выберите поле по причине и измените свойство "Обновить проверку" на "Никогда".

Ответ 3

У меня была такая же проблема с SQL Server 2008, и опция подключения no count уже была обработана.

Вместо того, чтобы изменить свойство Update Check на Never (как предполагает Quintin), я установил его в значение WhenChanged и проблема была решена.

Ответ 4

Сначала запишите информацию о проблеме, какую строку и какое поле конфликтуют и какие значения находятся в конфликте.

Чтобы реализовать такой подробный журнал, см. мое решение здесь:

Что я могу сделать, чтобы разрешить "Строка не найдена или изменена" ? Исключение в LINQ to SQL в базе данных SQL Server Compact Edition?