[英]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.AbpUowActiogerNotification(任务任务)位于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
是一个可以轻松使用IRepository
的Entity
,但不必一定是:
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
表:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.