首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EF审计创新

EF审计创新
EN

Stack Overflow用户
提问于 2016-02-05 10:08:20
回答 3查看 1.4K关注 0票数 1

好的,这里发生了很多事情,我不想用一个冗长的代码样本来烦你们,所以这里有一个摘录.

当在我的EF上下文中调用SaveChangesAsync()时,我让它调用此方法来审计每个条目.

代码语言:javascript
复制
async Task Audit(DbEntityEntry<IAmAuditable> entry)
{
    try
    {
        var newAuditEntry = new AuditEntry
        {
            EntityType = entry.Entity.GetType().Name,
            Event = entry.State.ToString(),
            SSOUserId = kernel.Get<User>().Id,
            EntityId = entry.GetId().ToString(),
            EventId = eventId
        };

如果所讨论的条目是实体创建,将导致在db上插入,那么我也这样做.

代码语言:javascript
复制
var properties = entry.CurrentValues.PropertyNames.Select(p => entry.Property(p)).ToList();
var addedValues = new List<AuditDataItem>();

foreach (var p in properties)
{
    addedValues.Add(new AuditDataItem
    {
        PropertyName = p.Name,
        PreviousValue = null,
        NewValue = p.CurrentValue.ToString()
    });
}
newAuditEntry.Changes = addedValues;
break;

..。它就在这里倒下..。此时,对SaveChanges的基调用尚未执行,因此所涉实体还没有主键值.最终的结果是,我记录了一个没有主实体的实体的创建。

有没有人建议一个很好的、干净的方法来处理这个问题,这样我就可以将新的主键值输入到AuditDataItem中了?

编辑:

下面是我作为json记录的一个例子,这是一个AuditEntry对象和一些子AuditDataItem行的一部分.

代码语言:javascript
复制
   {
      "Id": 4,
      "SSOUserId": 1,
      "EventId": "6d862aad-0898-4794-aea0-00af6f2994ff",
      "EntityType": "AC_Programme",
      "Event": "Added",
      "TimeOfEvent": "2016-02-04T12:04:31.5501508+01:00",
      "Changes": [
        {
          "Id": 34,
          "PropertyName": "Id",
          "PreviousValue": null,
          "NewValue": "0"
        },
        {
          "Id": 35,
          "PropertyName": "Name",
          "PreviousValue": null,
          "NewValue": "Test"
        },
        ...
      ]
    }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-02-05 15:23:38

好吧,这就是我想出来的.很想知道你们是怎么想的。

代码语言:javascript
复制
public override async Task<int> SaveChangesAsync()
{
    try
    {
        await AuditChanges(new[] { EntityState.Modified, EntityState.Deleted });
        var result = await base.SaveChangesAsync();
        await AuditChanges(new[] { EntityState.Added });
        return result;
    }
    catch (DbEntityValidationException ex) { throw ConstructDetailsFor(ex); }
}

async Task AuditChanges(EntityState[] states)
{
    var auditableEntities = ChangeTracker.Entries<IAmAuditable>()
        .Where(e => states.Contains(e.State));

    foreach (var entry in auditableEntities)
        await Audit(entry);
}

async Task Audit(DbEntityEntry<IAmAuditable> entry)
{
    ...

这是非常简单的:)

然后,我的审计方法基本上输入一个switch语句,并根据从变更跟踪器传入的可审计实体条目来决定运行什么逻辑。

我不认为审计能比这简单得多。

我将它放入一个泛型基类中,用于我的所有EF上下文,并运行一个迁移将其应用于所有db和bang .任何地方都可以对所有标记为"IAmAuditable“(空标记接口)的实体进行动态的自动审核。

我考虑使用一个属性,但这需要反射和什么不需要。

票数 0
EN

Stack Overflow用户

发布于 2016-02-05 10:40:12

据我所知,在对象被创建之后,没有任何事件可以调解对象的创建。有下列活动:

第一种情况发生在保存更改之前(与您遇到的问题相同)。第二种情况发生在查询或.Load结果从数据库中读取实体时,因此它不适合您的情况。

我能想到的唯一解决方案是覆盖原始的SaveChanges,并在重写的方法中这样做:

  • 查找所有处于添加状态的实体,并保持对它们的引用,例如将它们添加到List<Object>
  • 调用基本保存更改,以便在数据库中实现更改,并更新DbCOntext中的实体
  • 访问列表中的实体,您将获得所有db生成的属性(如计算、标识、guid等),以便正确地记录它们

日志记录和拦截数据库操作(EF6以后)不适合你的需要

票数 1
EN

Stack Overflow用户

发布于 2016-02-05 13:34:23

您需要将ObjectStateEntry保存在AuditEntry中,然后重新访问在PostSaveChanges事件中主键为“临时”的每个AuditEntry。

下面是一个示例:

显然,我建议您在创建自己的库时使用EF+审核,但是如果您仍然希望对其进行编码,则库是开源的,因此您将能够找到大量的信息来帮助您。

免责声明:我是项目EF+ (EntityFramework Plus)的所有者

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35221339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档