Инициализировать общие свойства объектов - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть много моделей сущностей, в которых все они имеют некоторые общие свойства, которые приведены ниже

  1. CreatedOn
  2. CreateBy
  3. LastModifiedon
  4. LastmodifiedBy

Каждый раз, когда мне нужно сохранить объект в базе данных, я должен инициализировать эти свойства вручную. Я хочу методы или некоторый базовый класс, где я могу инициализировать эти свойства, чтобы избежать хлопот написания одного и того же кода снова и снова. ПРИМЕЧАНИЕ: я хочу универсальную реализацию базового класса без базового конструктора. Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Вы не можете сделать это с вашим классом сущности по ряду причин.CreatedOn может быть обработано по умолчанию, но для остальных требуются знания, которых у класса сущностей никогда не будет, например, HttpContext.User или просто ли он был изменен или создан.

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

Затем вы можете добавить приватный метод в свой контекстный класс, например:

private void PopulateAuditTrailProperties()
{
    var httpContextAccessor = this.GetService<IHttpContextAccessor>();
    var username = httpContextAccessor?.HttpContext.User.Identity.Name;

    foreach (var entry in ChangeTracker.Entries<IEntity>().Where(x => x.State == EntityState.Added))
    {
        entry.Entity.CreatedOn = DateTimeOffset.UtcNow;
        entry.Entity.CreatedBy = username;
    }

    foreach (var entry in ChangeTracker.Entries<IEntity>().Where(x => x.State == EntityState.Modified))
    {
         entry.Entity.ModifiedOn = DateTimeOffset.UtcNow;
         entry.Entity.ModifiedBy = username;
     }
}

Затем вам нужно переопределить SaveChanges и SaveChangesAsync в вашем контексте, чтобы каждый вызов вызывал этот метод перед сохранением:

public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
    PopulateAuditTrailProperties();
    return base.SaveChanges(acceptAllChangesOnSuccess);
}

public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
    PopulateAuditTrailProperties();
    return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}

Наконец, вынужно добавить пару вещей к вашему Startup.cs:

services.AddDbContext<MyContext>(o =>
    o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
        .UseInternalServiceProvider()); // Add this line

И:

services.AddHttpContextAccessor();
0 голосов
/ 12 ноября 2018

Лично я бы использовал определение интерфейса. Все ваши сущности будут реализовывать интерфейс под названием IAuditedEntity (или любое другое имя, которое вы считаете подходящим). Интерфейс объявит ваши четыре свойства (CreatedOn, CreateBy, LastModifiedOn, LastModifiedBy) как get и set. Любой объект, которому требуются эти поля, должен будет реализовать интерфейс.

Затем, когда ваша запись обновляется в базе данных, проверьте, реализует ли объект интерфейс IAuditEntity, например if (myRecord is IAuditedEntity). Если он реализует интерфейс, установите свойства в соответствующие значения.

В этом сценарии лучше привести объект в интерфейс, чтобы обеспечить безопасность типов.

например. ((IAuditedEntity) myObj) .CreatedOn = DateTime.Now.

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

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

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