如何获取实体table每一行的AbpEntityChanges数据?

How to get AbpEntityChanges data for each row of the entity table?

我的应用程序需要通过单击行中的按钮来显示产品每一行的实体更改日志 table。但是我不知道如何从 abpEntityChanges table.

中获取审计数据

前端需要的DTO:

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;

namespace App.Products
{
    public class EntityChangeDto : EntityDto<Guid> {
        
        public Guid AuditLogId {get; set;}
        public string EntityId {get; set;}
        public EntityChangeType ChangeType {get;set;}
        public DateTime ChangeTime {get; set;}
        public string UserName {get; set;}

    }
}

所以我先尝试做IEntityChangeRepository(派生自审计模块的EntityChangeclass),希望能在AppService中使用GetQueryableAsync

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.AuditLogging;

namespace App.Products
{
    public interface IEntityChangeRepository : IRepository<EntityChange,Guid>
    {
        // need anything else here?
    }
}

然后在我的 ProductAppService(当然还有 IProductAppService)中添加了新任务 GetEntityChangeListAsync

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AuditLogging;

namespace App.Products
{
    public class ProductAppService :
        CrudAppService<Product,ProductDto,Guid,GetProductListDto,CreateUpdateProductDto>,
        IProductAppService
    {
        private readonly IEntityChangeRepository _entityChangeRepository;
        private readonly IAuditLogRepository _auditLogRepository;

        public ProductAppService(
          IRepository<Product, Guid> repository
          IEntityChangeRepository entityChangeRepository,
          IAuditLogRepository auditLogRepository
        )
            : base(repository)
            {
                _entityChangeRepository = entityChangeRepository;
                _auditLogRepository = auditLogRepository;
            }
         
         public async Task<ListResultDto<EntityChangeDto>> GetEntityChangeListAsync(string id) {
            
             var queryable = await _entityChangeRepository.GetQueryableAsync();

             queryable = queryable
             .Where(p => p.EntityId.Equals(id))
             .OrderBy(p => p.ChangeTime);

             var query = from entityChange in queryable
                 join auditLog in _auditLogRepository on entityChange.AuditLogId equals auditLog.Id
                 select new { entityChange, auditLog };

             var queryResult = await AsyncExecuter.ToListAsync(query);

             var entityChangeDtos = queryResult.Select(x =>
                {
                    var entityChangeDto = ObjectMapper.Map<EntityChange,EntityChangeDto>(x.entityChange);
                    entityChangeDto.UserName = x.auditLog.UserName;
                    return entityChangeDto;
                }).ToList();
   
                return new ListResultDto<EntityChangeDto>(
                    entityChangeDtos
                );
            }
    }
}

但我不断收到错误代码 500。而且我认为问题很可能出在 IEntityChangeRepository 上。缺少某些映射或存储库无法通过这种方式查询? 有人可以帮忙吗?非常感谢 ^^ 我是编码领域的初学者,但我研究了 abp 文档,但无法解决它:)

错误日志

2021-03-25 07:59:20.505 +01:00 [ERR] An exception was thrown while activating Castle.Proxies.ProductAppServiceProxy.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Castle.Proxies.ProductAppServiceProxy.
 ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Volo.Abp.Autofac.AbpAutofacConstructorFinder' on type 'Castle.Proxies.ProductAppServiceProxy' can be invoked with the available services and parameters:
Cannot resolve parameter 'App.Products.IEntityChangeRepository entityChangeRepository' of constructor 'Void .ctor(Castle.DynamicProxy.IInterceptor[], Volo.Abp.Domain.Repositories.IRepository`2[App.Products.Product,System.Guid], App.Products.IEntityChangeRepository, Volo.Abp.AuditLogging.IAuditLogRepository)'.
   at Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[] availableConstructors, IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext ctxt, Action`1 next)
   at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass41_0.<PropertiesAutowired>b__0(ResolveRequestContext ctxt, Action`1 next)
   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   --- End of inner exception stack trace ---
   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass35_0.<OnPreparing>b__0(ResolveRequestContext ctxt, Action`1 next)
   at Autofac.Core.Resolving.Middleware.CoreEventMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
   at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2021-03-25 07:59:20.507 +01:00 [ERR] ---------- Exception Data ----------
ActivatorChain = Castle.Proxies.ProductAppServiceProxy

这将帮助您找到方向;

public class EfCoreAuditLogRepository : EfCoreRepository<IAuditLoggingDbContext, AuditLog, Guid>, IAuditLogRepository
    {
        public EfCoreAuditLogRepository(IDbContextProvider<IAuditLoggingDbContext> dbContextProvider)
            : base(dbContextProvider)
        {

        }

        public override async Task<IQueryable<AuditLog>> WithDetailsAsync()
        {
            return (await GetQueryableAsync()).IncludeDetails();
        }

        public virtual async Task<EntityChange> GetEntityChange(
            Guid entityChangeId,
            CancellationToken cancellationToken = default)
        {
            var entityChange = await (await GetDbContextAsync()).Set<EntityChange>()
                                    .AsNoTracking()
                                    .IncludeDetails()
                                    .Where(x => x.Id == entityChangeId)
                                    .OrderBy(x => x.Id)
                                    .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));

            if (entityChange == null)
            {
                throw new EntityNotFoundException(typeof(EntityChange));
            }

            return entityChange;
        }

        public virtual async Task<List<EntityChange>> GetEntityChangeListAsync(
            string sorting = null,
            int maxResultCount = 50,
            int skipCount = 0,
            Guid? auditLogId = null,
            DateTime? startTime = null,
            DateTime? endTime = null,
            EntityChangeType? changeType = null,
            string entityId = null,
            string entityTypeFullName = null,
            bool includeDetails = false,
            CancellationToken cancellationToken = default)
        {
            var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, includeDetails);

            return await query.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(EntityChange.ChangeTime) + " DESC") : sorting)
                .PageBy(skipCount, maxResultCount)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public virtual async Task<long> GetEntityChangeCountAsync(
            Guid? auditLogId = null,
            DateTime? startTime = null,
            DateTime? endTime = null,
            EntityChangeType? changeType = null,
            string entityId = null,
            string entityTypeFullName = null,
            CancellationToken cancellationToken = default)
        {
            var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName);

            var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken));

            return totalCount;
        }

        public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(
            Guid entityChangeId,
            CancellationToken cancellationToken = default)
        {
            var auditLog = await (await GetDbSetAsync()).AsNoTracking().IncludeDetails()
                .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(GetCancellationToken(cancellationToken));

            return new EntityChangeWithUsername()
            {
                EntityChange = auditLog.EntityChanges.First(x => x.Id == entityChangeId),
                UserName = auditLog.UserName
            };
        }

        protected virtual async Task<IQueryable<EntityChange>> GetEntityChangeListQueryAsync(
            Guid? auditLogId = null,
            DateTime? startTime = null,
            DateTime? endTime = null,
            EntityChangeType? changeType = null,
            string entityId = null,
            string entityTypeFullName = null,
            bool includeDetails = false)
        {
            return (await GetDbContextAsync())
                .Set<EntityChange>()
                .AsNoTracking()
                .IncludeDetails(includeDetails)
                .WhereIf(auditLogId.HasValue, e => e.AuditLogId == auditLogId)
                .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime)
                .WhereIf(endTime.HasValue, e => e.ChangeTime <= endTime)
                .WhereIf(changeType.HasValue, e => e.ChangeType == changeType)
                .WhereIf(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId)
                .WhereIf(!string.IsNullOrWhiteSpace(entityTypeFullName), e => e.EntityTypeFullName.Contains(entityTypeFullName));
        }
    }