TimeStamp с EF Core 2.1 и Sql Server? - PullRequest
       22

TimeStamp с EF Core 2.1 и Sql Server?

4 голосов
/ 15 марта 2019

Я хочу, чтобы в большинстве моих таблиц был столбец «Последнее обновление», чтобы я мог быстро проверить, когда оно обновлялось в последний раз.

Сейчас я просто выставляю дату и время каждый раз, когда делаюдействие в моем коде C #, я сохраню новый DateTime для обновления этого поля.Конечно, это может привести к тому, что я забуду это сделать.

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

Я пытался

builder.Property(x => x.RowVersion).IsRowVersion();

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

edit

 public class CompanyConfig : IEntityTypeConfiguration<Company>
    {
        public void Configure(EntityTypeBuilder<Company> builder)
        {
            builder.HasKey(x => x.Id);
            builder.Property(x => x.Id).ValueGeneratedOnAdd();
            builder.Property<DateTime>("LastUpdated");
        }
    }

Ответы [ 3 ]

3 голосов
/ 21 марта 2019

Предполагая, что вы определили теневое свойство LastModified для каждой сущности, для которой вы хотите эту функциональность, как в вашем примере

builder.Property<DateTime>("LastUpdated");

и вопрос в том, как обновить его автоматически.

Техника, описанная в ответе Давида, устарела. Все еще возможно переопределить SaveChangesSaveChangesAsync), но есть ИМХО лучший подход, показанный в Автоматически заполнять и создавать в EF Core . Это интерфейсный подход, но его можно легко настроить для свойства shadow (или любого свойства - используемые методы работают как для shadow, так и для явных свойств).

Краткий обзор: начиная с версии 2.1 EF Core предоставляет События изменения состояния :

Новые Tracked и StateChanged события на ChangeTracker могут использоваться для записи логики, которая реагирует на объекты, входящие в DbContext или изменяющие их состояние.

Вот как вы можете их использовать. Добавьте следующее в ваш производный контекстный класс:

void SubscribeStateChangeEvents()
{
    ChangeTracker.Tracked += OnEntityTracked;
    ChangeTracker.StateChanged += OnEntityStateChanged;
}

void OnEntityStateChanged(object sender, EntityStateChangedEventArgs e)
{
    ProcessLastModified(e.Entry);
}

void OnEntityTracked(object sender, EntityTrackedEventArgs e)
{
    if (!e.FromQuery)
        ProcessLastModified(e.Entry);
}

void ProcessLastModified(EntityEntry entry)
{
    if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
    {
        var property = entry.Metadata.FindProperty("LastModified");
        if (property != null && property.ClrType == typeof(DateTime))
            entry.CurrentValues[property] = DateTime.UtcNow;
    }
}

и добавьте

SubscribeStateChangeEvents();

к вашему производному контекстному конструктору (ам).

И это все. Как только контекст подписан на эти события, он будет уведомлен в любое время, когда сущность изначально отслеживается или ее состояние изменяется. Вас интересует только состояние Modified и Added, не вызванное материализацией запроса (если вам не нужен Added, просто исключите его из условия if). Затем вы проверяете, содержит ли объект свойство DateTime LastModified, используя службы метаданных EF Core, и если да, просто обновите его с текущей датой / временем.

1 голос
/ 15 марта 2019

Шаблон в EF Core для этого состоит в том, чтобы сделать LastUpdated Shadow Property и обновить его во время SaveChanges ().

См., Например: Реализация общих полей аудита с помощью свойства Shadow EF Core

0 голосов
/ 27 марта 2019

Посмотрев документацию по классу DbContext , вы можете переопределить метод SaveChanges и установить там значения LastUpdated, прежде чем продолжить с base.SaveChanges() в конце.

Один последний элемент - внутри SaveChanges метода, вы можете найти измененные / вновь добавленные объекты, используя свойство ChangeTracker .

...