Проблемы с типом DataTime маркера параллелизма Entity Framework - PullRequest
3 голосов
/ 21 февраля 2012

У меня проблема с токеном параллелизма DateTime.Вот простой способ воспроизвести проблему.Имеется одна сущность:

public class Employee
{
    public int EmployeeID { get; set; }
    public string Name { get; set; }
    [ConcurrencyCheck]
    public DateTime LastModified { get; set; }
}

Тривиальный DbContext:

public class MyContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
}

И следующий код:

Employee orig;

//  Create a row (insert)
using (var context = new MyContext())
{
    orig = new Employee
    {
        Name = "Mike",
        LastModified = DateTime.Now
    };
    context.Employees.Add(orig);

    context.SaveChanges();
}
//  Update the row, passing the right concurrency token
using (var context = new MyContext())
{
    var clone = new Employee
    {
        EmployeeID = orig.EmployeeID,
        Name = "Suzanne",
        //  Pass the concurrency token here
        LastModified = orig.LastModified
    };
    context.Employees.Attach(clone);
    //  Mark the entity as modified to force an update
    context.Entry(clone).State = EntityState.Modified;

    //  Boom!  Currency exception!
    context.SaveChanges();
}

По сути, я создаю сотрудника, а затем обновляю его,Взрыв!Я смотрю на оператор обновления, сгенерированный на SQL (профилирование):

exec sp_executesql N'update [dbo].[Employees]
set [Name] = @0, [LastModified] = @1
where (([EmployeeID] = @2) and ([LastModified] = @3))
',N'@0 nvarchar(max) ,@1 datetime2(7),@2 int,@3 datetime2(7)',@0=N'Suzanne',@1='2012-02-21 
12:06:30.0141536',@2=0,@3='2012-02-21 12:06:30.0141536'

Мне кажется, что это утверждение звучит нормально, но оно не выполняется, то есть оно изменяет нулевую строку, как если бы ([LastModified] = @ 3) произошел сбой.

Я подозреваю, что существует «проблема точности», то есть количество цифр не соответствует сохраненному.Может ли быть несоответствие между представлением DateTime в .NET и SQL?

Я пытался использовать System.Data.SqlTypes.SqlDateTime вместо DateTime в моем классе Poco, надеясь, что это будет иметь правильную точность, но яне смог отобразить его, EF всегда оставлял свойство не отображенным.

Решения?

1 Ответ

4 голосов
/ 23 февраля 2012

Я нашел проблему! На самом деле здесь есть две проблемы: техническая и семантическая.

Техническая проблема заключается в том, что EF по какой-либо причине отправляет System.DateTime как тип SQL datetime (2) в SQL. По умолчанию он отображает System.DateTime как datetime. На самом деле мне не удалось заставить EF создать базу данных с datetime (2), несмотря на то, что тип SQL был преобразован в datetime (2). Но если вы измените это после факта, это решит проблему. Таким образом, проблема была действительно проблемой точности.

Семантическая проблема в том, что целое не имеет смысла, если вы об этом думаете. Токен параллелизма - это то, что вам нужно передать в SQL, чтобы доказать, что вы последний прочитали таблицу. Однако токен параллелизма необходимо обновлять каждый раз при обновлении строки. Один исключает другой: если вы попытаетесь обновить LastModified до DateTime.Now, у вас будет исключение для параллелизма, поскольку токен параллелизма не хранится в строке!

Так что, несмотря на поиск решения технической проблемы, вся эта схема не имеет смысла.

... если только! Вы найдете способ обновить столбец LastModified без использования EF. Например, у вас может быть триггер. Как правило, вы бы не хотели туда идти.

...