Шаблон репозитория и реализация журнала изменений - PullRequest
1 голос
/ 06 октября 2019

У меня есть API, созданный с помощью .net core 2, и я пытаюсь реализовать функцию журнала изменений.

Я выполнил базовую часть, но я не уверен, что это лучший способ сделать это.

Вот мой EntityBaseRepository

public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IFullAuditedEntity, new()
{
    private readonly ApplicationContext context;

    public EntityBaseRepository(ApplicationContext context)
    {
        this.context = context;
    }

    public virtual IEnumerable<T> items => context.Set<T>().AsEnumerable().OrderByDescending(m => m.Id);

    public virtual T this[int id] => context.Set<T>().FirstOrDefault(m => m.Id == id);

    public virtual T GetSingle(int id) => context.Set<T>().FirstOrDefault(x => x.Id == id);

    public virtual T Add(T entity) => Operations(entity: entity, state: EntityState.Added);

    public virtual T Update(T entity) => Operations(entity: entity, state: EntityState.Modified);

    public virtual T Delete(T entity) => Operations(entity: entity, state: EntityState.Deleted);

    public virtual T Operations(T entity, EntityState state)
    {
        EntityEntry dbEntityEntry = context.Entry<T>(entity);

        if (state == EntityState.Added)
        {
            entity.CreationDateTime = DateTime.UtcNow;
            entity.CreationUserId = 1;

            context.Set<T>().Add(entity);
            dbEntityEntry.State = EntityState.Added;
        }
        else if (state == EntityState.Modified)
        {
            entity.LastModificationDateTime = DateTime.UtcNow;
            entity.LastModificationUserId = 1;

            var local = context.Set<T>().Local.FirstOrDefault(entry => entry.Id.Equals(entity.Id));
            if (local != null)
            {
                context.Entry(local).State = EntityState.Detached;
            }

            dbEntityEntry.State = EntityState.Modified;
        }
        else if (state == EntityState.Deleted)
        {
            entity.DeletionFlag = true;
            entity.DeletionUserId = 1;
            entity.DeletionDateTime = DateTime.UtcNow;

            dbEntityEntry.State = EntityState.Modified;
        }

        return entity;
    }

Вот один из моих контроллеров.

[Produces("application/json")]
[Route("api/Item")]
public class ItemController : Controller
{
    private readonly IItemRepository repository;
    private readonly IChangeLogRepository changeLogRepository;
    private readonly IMapper mapper;

    public ItemController(IItemRepository repository, IChangeLogRepository _changeLogRepository, IMapper mapper)
    {
        this.repository = repository;
        this.changeLogRepository = _changeLogRepository;
        this.mapper = mapper;
    }

    [HttpPost]
    public IActionResult Post([FromBody]ItemDto transactionItemDto)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var item = repository.Add(mapper.Map<ItemDto, Item>(source: transactionItemDto));
        repository.Commit();

        ChangeLog log = new ChangeLog()
        {
            Log = "New Item Added"
        };

        changeLogRepository.Add(log);
        changeLogRepository.Commit();

        return new OkObjectResult(mapper.Map<Item, ItemDto>(source: item));
    }
}

если вы видите в контроллере, я добавил один элемент и зафиксировал его,затем я подготовил журнал для этой вставки, добавил и зафиксировал его.

Теперь у меня есть несколько вопросов, например

  1. Мне нужно дважды совершить транзакцию ,Есть ли способ, которым я могу оптимизировать это? Я не знаю, смогу ли я справиться с этим в EntityBaseRepository или нет.
  2. Я также хочу проверить каждое свойство, если оно изменилось или нет. Я хочу записать это, если оно изменилось. Каков наилучший способ справиться с этим?

Было бы здорово, если бы кто-нибудь мог помочь мне с этим. очень ценю. спасибо.

Ответы [ 2 ]

2 голосов
/ 06 октября 2019

Вы можете использовать фильтры действий для журнала изменений, например

using System;

public class TrackMyChange : IActionFilter
{
    private readonly string _chengeMessage;
    private readonly IChangeLogRepository _changeLogRepository;
    public TrackMyChange(string changeMessage,IChangeLogRepository changeLogRepository)
    {
        this._changeLogRepository = changeLogRepository;
        this._chengeMessage = chengeMessage;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
    // Do something before the action executes.
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        ChangeLog log = new ChangeLog()
        {Log = this._chengeMessage};
        changeLogRepository.Add(log);
        changeLogRepository.Commit();
    }
}

В вашем контроллере вы можете использовать его до действий, которые вы хотите зарегистрировать, например

[TrackMyChange("Your change log here")]
public IActionResult Post()
{
}

Ссылка: Атрибуты фильтра действий в ядре .NET

1 голос
/ 07 октября 2019
  1. DbContext используется несколькими хранилищами в одной и той же области HTTP-запроса. Вам не понадобится UoW. Просто попробуйте использовать один Commit () и посмотрите, все ли изменения сохранены в одной транзакции.

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-implemenation-entity-framework-core

Используйте yourDbContext.Entry (your_entity_obj) .State , чтобы получить состояние объекта. Не регистрируйте, если его состояние EntityState.Unchanged .

https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entitystate?view=efcore-2.1

...