Почему я не могу перезаписать определенное поле через Entity Framework? - PullRequest
0 голосов
/ 31 мая 2018

Я работаю над приложением ASP.NET MVC, которое использует Entity Framework.Я хочу изменить поле CreatedOn в таблице Users.

Следующий код

    using (var db = new MainDB())
    {   
        var theUser = db.Users.Single(u => u.LoginName == model.User.LoginName);
        theUser.CreatedOn = new DateTime(2017, 1, 1); // this does not save
        theUser.CF20 = "test20";
        db.SaveChanges();   
    }

меняет поле CF20 на "test20", но не меняет поле CreatedOn.

Я предполагаю, чтоПоле CreatedOn получает какой-то особый статус и функциональность где-то, что заполняет его временной меткой при создании записи и которое не позволяет впоследствии ее изменить.

Я не могу найти, где это происходит вкод, поэтому я предполагаю, что он находится где-то в моделях Entity Framework, настройках и т. д.

Где я могу найти, чтобы узнать, где он устанавливается и как я могу изменить его после того, как он был установлен?

Приложение

Например, я нашел в файле .edmx в <EntityType Name="Users"> строку <Property Name="CreatedOn" Type="datetime" Nullable="false" StoreGeneratedPattern="Computed" /> и изменил ее на <Property Name="CreatedOn" Type="datetime" Nullable="false" />, но она все равно вычисляет дату какdatetime и не изменит его.

И вывод необработанного SQL, я вижу, что в операторе update он оставляет CreatedOn вне: мой вывод SQL показывает:

UPDATE [dbo].[Users]
SET [LoginName] = @0,
    [Password] = @1,
    [PasswordSalt] = @2,
    [LastLoginIP] = NULL,
    [Status] = @3,
    [Email] = @4,
    [FailedLoginAttempts] = NULL,
    [CF01] = NULL,
    [CF02] = NULL,
    [CF03] = NULL,
    [CF04] = NULL,
    [CF05] = NULL,
    [CF06] = NULL,
    [CF07] = NULL,
    [CF08] = NULL,
    [CF09] = NULL,
    [CF10] = NULL,
    [LanguageID] = @5,
    [CF11] = NULL,
    [CF12] = NULL,
    [CF13] = NULL,
    [CF14] = NULL,
    [CF15] = NULL,
    [CF16] = NULL,
    [CF17] = NULL,
    [CF18] = NULL,
    [CF19] = @6,
    [CF20] = @7,
    [MustChangePassword] = NULL
WHERE ([ID] = @8)

1 Ответ

0 голосов
/ 31 мая 2018

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

Обновление после обсуждения:

Вот минимальное решение, в котором значение по умолчанию корректно обновляется по требованию.

Сначала создайте новую таблицу на SQL Server:

CREATE TABLE [dbo].[DateDefaultTest](
    [AnId] [int] IDENTITY(1,1) NOT NULL,
    [CreatedOn] [datetime2](7) NOT NULL,
    [SomeField] [nvarchar](50) NULL,
 CONSTRAINT [PK_DateDefaultTest] PRIMARY KEY CLUSTERED 
(
    [AnId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[DateDefaultTest] ADD  CONSTRAINT [DF_DateDefaultTest_CreatedOn]  DEFAULT (getutcdate()) FOR [CreatedOn]
GO

Поле идентификатора имеет видавтоинкрементный первичный ключ, строковое поле и интересующее нас поле CreatedOn. Мы добавили ограничение DEFAULT, чтобы установить для него текущую дату и время UTC.

Далее создайте консольприложение, добавьте EF через NuGet и настройте DbContext как обычно.Я назвал свой контекст DefaultTestEntities.

Сгенерированный код для сущности выглядит следующим образом:

public partial class DateDefaultTest
{
    public int AnId { get; set; }
    public System.DateTime CreatedOn { get; set; }
    public string SomeField { get; set; }
}

На странице свойств диаграммы EF для поля CreatedOn ничего не имеетбыл изменен.

Используйте следующий код для добавления пары строк:

using (var db = new DefaultTestEntities())
{
    db.DateDefaultTests.Add(new DateDefaultTest
    {
         SomeField = "Bananas"
    });
    db.DateDefaultTests.Add(new DateDefaultTest
    {
         SomeField = "Apples",
    });

    db.SaveChanges();
}

Они должны появиться в таблице с текущими датой и временем, установленными, как и ожидалось.

Как вы обнаружили, если вы попытаетесь установить CreatedOn вручную при вставке новой строки, это не будет работать из-за ограничений SQL Server.Например:

db.DateDefaultTests.Add(new DateDefaultTest
{
     SomeField = "Pears",
     CreatedOn = DateTime.UtcNow.AddHours(1)
});

приведет к бессмысленной дате '0001-01-01'.

Вам придется обновить существующую строку, если вы хотите установить CreatedOnв явном виде.Для этого:

db.DateDefaultTests
    .Where(x => x.SomeField == "Bananas")
    .First()
    .CreatedOn = DateTime.UtcNow.AddDays(-1);
db.SaveChanges();

Если это не относится к вашей ситуации, я бы порекомендовал вам:

  • Проверьте свой столбец в SQL Server, чтобы убедиться, что значение не соответствуетcomputed
  • Восстановить модель
  • Подтвердить, что в вашем коде нет переопределений EF, которые могут повлиять на значение при сохранении сущности

Извинения за комментарийгде я сказал EF не будет обновлять столбцы по умолчанию.Это неверно и относится только к начальной вставке.

Обновление - необходимые настройки:

SQL Server CreatedOn Settings

EDMX CreatedOn Settings

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