简体   繁体   English

将属性值存储到另一个表中

[英]Storing a property value into another table

I am looking for a way to copy the value of some properties of a class to another table in DB. 我正在寻找一种将类的某些属性的值复制到DB中的另一个表的方法。 Is there any particular way that I can mark properties of a class as one which their values need to be stored in 2 places (one as part of its own domain object and the other in another domain object, say Summary)? 有什么特别的方法可以将一个类的属性标记为一个属性,它们的值需要存储在2个地方(一个作为其自己的域对象的一部分,而另一个存储在另一个域对象中,例如Summary)?

I a having a Audited entity as below: 我拥有一个经审计的实体,如下所示:

public class Audited 
{
    public virtual int Id{ get; set; }

    public virtual string FieldName{ get; set; }

    public virtual string FieldValue{ get; set; }
}

And other entities such as: 和其他实体,例如:

public class Plan : FullAuditedEntity
{
    [ToBeAudited]
    public virtual int PlanName{ get; set; }

    public DateTime Date { get; set; }
}

I am looking for a way to be able to mark properties of classes with an attribute (eg. [ToBeAudited]) so that property value gets copied into the Audited table in on insert or update 我正在寻找一种方法来标记带有属性的类的属性(例如[ToBeAudited]),以便在插入或更新时将属性值复制到Audited表中

I have added the [Audited] ( Abp.Auditing ) to PlanName and getting the following error in log: 我已经将[Audited]( Abp.Auditing )添加到PlanName并在日志中得到以下错误:

ERROR 2018-04-20 10:02:09,286 [5 ] Mvc.ExceptionHandling.AbpExceptionFilter - Object reference not set to an instance of an object. 错误2018-04-20 10:02:09,286 [5] Mvc.ExceptionHandling.AbpExceptionFilter-对象引用未设置为对象的实例。 System.NullReferenceException: Object reference not set to an instance of an object. System.NullReferenceException:对象引用未设置为对象的实例。 at Abp.EntityHistory.EntityHistoryHelper.ShouldSavePropertyHistory(PropertyEntry propertyEntry, Boolean defaultValue) at Abp.EntityHistory.EntityHistoryHelper.GetPropertyChanges(EntityEntry entityEntry) at Abp.EntityHistory.EntityHistoryHelper.CreateEntityChangeInfo(EntityEntry entityEntry) at Abp.EntityHistory.EntityHistoryHelper.CreateEntityChangeSet(ICollection 1 entityEntries) at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext 3.d__98.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__20.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebug 在Abp.EntityHistory.EntityHistoryHelper.ShouldSavePropertyHistory(PropertyEntry propertyEntry,布尔默认值)在Abp.EntityHistory.EntityHistoryHelper.GetPropertyChanges(EntityEntry entityEntry)在Abp.EntityHistory.EntityHistoryHelper.CreateEntityChangeInfo(EntityEntry entityEntry)在Abp.EntityHistory.EntityHistoryHelper.CreateEntityChangeSet(ICollection的1 entityEntries) at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext 3.d__98.MoveNext()的1 entityEntries) at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext条目-从上次引发异常的位置开始的堆栈跟踪-在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__20.MoveNext()处的.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)---从上次引发异常的位置开始的堆栈结束跟踪---在System.Runtime.CompilerServices。 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebug处的TaskAwaiter.ThrowForNonSuccess(任务任务) gerNotification(Task task) at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Domain.Uow.UnitOfWorkBase.d__57.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.AspNetCore.Mvc.Uow.AbpUowActio gerNotification(任务任务)位于Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__12.MoveNext()-从上次引发异常的位置开始的堆栈跟踪-在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)在Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.d__14.MoveNext()-从上次引发异常的位置开始的堆栈结束-在System.Runtime。 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)处的CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)位于Abp.Domain.Uow.UnitOfWorkBase.d__57.MoveNext()的堆栈任务-从上一个异常发生的位置开始的堆栈跟踪在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)处抛出-在Abp.AspNetCore.Mvc.Uow.AbpUowActio nFilter.d__4.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Micros nFilter.d__4.MoveNext()-从上一个引发异常的位置开始的堆栈跟踪--在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext()的任务)-从上一个引发异常的位置开始的堆栈跟踪-在Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext上下文) )(Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext()处的状态(Next&State,Scope&Scope,Object&state,Boolean&isCompleted)---从堆栈结束跟踪引发异常的先前位置---在Micros的System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)处的System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) oft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() oft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext()

You can leverage on ABP's Entity History feature (which already works without this customization). 您可以利用ABP的“ 实体历史记录”功能(无需进行此自定义即可使用)。

This answer assumes Audited is an Entity to easily use IRepository , but it doesn't have to be: 此答案假定Audited是一个可以轻松使用IRepositoryEntity ,但不必一定是:

public class Audited : Entity
{
    public virtual int EntityId { get; set; }

    public virtual string FieldName { get; set; }

    public virtual string FieldValue { get; set; }
}

First, implement IEntityHistoryStore : 首先,实现IEntityHistoryStore

public class MyEntityHistoryStore : IEntityHistoryStore
{
    private readonly IRepository<Audited> _auditedRepository;

    public MyEntityHistoryStore(IRepository<Audited> auditedRepository)
    {
        _auditedRepository = auditedRepository;
    }

    public async Task SaveAsync(EntityChangeSet entityChangeSet)
    {
        foreach (var entityChange in entityChangeSet.EntityChanges)
        {
            var entityType = entityChange.EntityEntry.As<EntityEntry>().Entity.GetType();

            foreach (var propertyChange in entityChange.PropertyChanges)
            {
                var property = entityType.GetProperty(propertyChange.PropertyName);
                if (property.IsDefined(typeof(ToBeAuditedAttribute)))
                {
                    await _auditedRepository.InsertAsync(new Audited
                    {
                        EntityId = JsonConvert.DeserializeObject<int>(entityChange.EntityId),
                        FieldName = propertyChange.PropertyName,
                        FieldValue = propertyChange.NewValue
                    });
                }
            }
        }
    }
}

Next, replace the service and add to Selectors in the PreInitialize method of your module: 接下来,替换服务,并在模块的PreInitialize方法中将其添加到Selectors

// using Abp.Configuration.Startup;

Configuration.ReplaceService<IEntityHistoryStore, MyEntityHistoryStore>();
Configuration.EntityHistory.Selectors.Add(
    new NamedTypeSelector(
        "ToBeAuditedEntities",
        type => type.GetProperties().Any(p => p.IsDefined(typeof(ToBeAuditedAttribute)))
    )
);

Then, just Insert as usual: 然后,像往常一样Insert

_planRepository.Insert(new Plan
{
    PlanName = 42
});

Audited table: Audited表:

Auditeds

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM