NET Core 3.1: обновлять поле объекта при вставке и обновлении

#c# #asp.net #asp.net-core-3.1

#c# #asp.net #asp.net-core-3.1

Вопрос:

Я создаю REST API в NET Core 3.1. У меня есть таблица с именем GrRefBancos со столбцами для аудита того, кто и когда вставляет или обновляет регистры. Как я могу заполнить эти столбцы автоматически без необходимости отправлять значения при выполнении вставки или обновления?

Это мой код:

 public abstract class BaseEntity
{
    public long Id { get; set; }
    public DateTime CreadoEl { get; set; }
    public string CreadoPor { get; set; }
    public DateTime? ActualizaEl { get; set; }
    public string ActualizaPor { get; set; }
    public DateTime? InactivaEl { get; set; }
}

public partial class GrRefBancos : BaseEntity
{
    public GrRefBancos()
    {
        IcFacturas = new HashSet<IcFacturas>();
        PrFacturas = new HashSet<PrFacturas>();
    }

    public string CodigoBanco { get; set; }
    public string Descripcion { get; set; }

    public virtual ICollection<IcFacturas> IcFacturas { get; set; }
    public virtual ICollection<PrFacturas> PrFacturas { get; set; }
}
  

В DbContext я попытался с HasDefaultValue() помощью функции вставить, но это не сработало:

 modelBuilder.Entity<GrRefBancos>(entity =>
            {
                entity.HasKey(e => e.Id)
                    .HasName("PK_grrefbancos")
                    .IsClustered(false);

                entity.Property(e => e.ActualizaEl).HasColumnType("datetime");

                entity.Property(e => e.ActualizaPor)
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.CodigoBanco)
                    .IsRequired()
                    .HasMaxLength(10)
                    .IsUnicode(false);

                entity.Property(e => e.CreadoEl)
                    .HasColumnType("datetime")
                    .HasDefaultValue(DateTime.Now);

                entity.Property(e => e.CreadoPor)
                    .IsRequired()
                    .HasMaxLength(50)
                    .HasDefaultValue("LoogedUser")
                    .IsUnicode(false);

                entity.Property(e => e.Descripcion)
                    .HasMaxLength(100)
                    .IsUnicode(false);

                entity.Property(e => e.InactivaEl)
                    .HasColumnName("InactivaEL")
                    .HasColumnType("datetime");
            });
  

Спасибо за ваше внимание.

Ответ №1:

Вам нужно будет переопределить SaveChanges() или SaveChangesAsync() . Затем вам нужно будет захватить ChangeTracker и запросить у него все записи объекта с помощью changeTracker.Entries() .

Выполните итерацию по возвращенной коллекции, проверьте Entry.State , является ли это вставкой или обновлением, и соответствующим образом измените столбцы аудита.

Вам DbContext необходимо будет знать о пользователе, который выполняет операцию, однако об этом легко позаботиться благодаря разумному использованию DI. Если DI невозможен из-за циклических зависимостей, затем вызовите событие из SaveChanges[Async]() переопределения выше и запросите имя пользователя.

PS: Вы можете решить не делать их частью своей модели, сделав столбцы аудита теневыми для свойств EF.

Комментарии:

1. Это решение работает для меня, я использовал ChangeTracker в dbcontext и переопределил функцию SaveChanges для обновления полей временных меток. Спасибо за ваш совет.

Ответ №2:

С помощью триггера в таблицах. И определять их как вычисленные в метамодели EFCore, чтобы Ef не пытался их обновлять.

Однако это не сработает, потому что при нормальной современной настройке с объединением в пул соединений база данных понятия не имеет, кто на самом деле является пользователем. Дата / временная метка «простая» — имя пользователя просто недоступно в серверной части.

Комментарии:

1. Спасибо за ответ. Вы правы, по триггеру не работает, потому что база данных не знает реального пользователя из приложения. Мне нужно сделать это с помощью кода. Я новичок в Net Core, и я искал решение, но в документе, который я прочитал, говорится, что для вставки определите значение по умолчанию с HasDefaultValue, но это тоже не работает

2. Нет. Вам нужно запрограммировать его в методы, в которых вы выполняете обновление. Или в SaveChanges, просматривая все изменения.

Ответ №3:

Вы можете реализовать эту функцию в своем классе BaseRepository

 class BaseRepository<T>{
     private readonly DbContext _dbContext;
     public BaseRepository(DbContext dbContext){
           _dbContext = dbContext;
     }
     public Update(T Entity, UserEntity userEntity){
            //Do anything you like here
     }
     public Insert(T Entity, UserEntity userEntity){
            //Do anything you like here
     }
}
  

и использовать его следующим образом

 _unitOfWork.GetRepository<MyRepository>().Update(MyEntity,UserEntity);
//or
_unitOfWork.GetRepository<MyRepository>().Insert(MyEntity,UserEntity);
  

Вы можете реализовать свои сервисы, чтобы сделать это автоматически, возможно, передать HttpContext.User!

 _myEntityService.Update(myDto,HttpContext.User);
//or
_myEntityService.Insert(myDto,HttpContext.User);
  

Это вызывающе возможно, и техническая реализация полностью зависит от того, чего вы действительно пытаетесь достичь.

Комментарии:

1. Сверните место (есть переопределение) И — предполагая, что кто-то использует шаблон репозитория, который является проверенным антишаблоном и который мне еще предстоит увидеть ДОЛЖНЫМ ОБРАЗОМ реализованным через 20 лет.

2. Спасибо, что поделились своим мнением @TomTom, вы абсолютно правы, однако я считаю, что общие репозитории полностью подходят для целей crud. Пример довольно упрощен, но не могли бы вы рассказать мне больше о проблеме реализации, о которой вы говорите. Я новичок, и я могу воспользоваться вашей помощью, чтобы отшлифовать код здесь.

3. Это бесполезный мертвый код для простых вещей (т. Е. Вы ничего не получаете — у вас ЕСТЬ репозиторий и единица работы, они называются DbContext. Как только вы попадаете в большее количество репозиториев compelx sceanrios, они полностью неисправны в 99,999% реализаций. Как и ваше обновление — я должен обновить только ОДНУ вещь, но как насчет элементов, на которые ссылаются? Как насчет загрузки — репозиторий не может должным образом обрабатывать включение без использования других репозиториев, о чем разработчики репозиториев, похоже, ВСЕГДА забывают. В конце концов, это тонна кода, без которого вы можете обойтись с точно такой же функциональностью. Добавление бесполезного кода = плохо.