审核日志记录插入

时间:2011-06-30 16:11:36

标签: c# entity-framework entity-framework-4.1

我想知道是否有人可以为插入的审计日志记录实现提供一些输入。我需要确保它是交易性的。

我有一个基于以下POCO构建的审计DbSet:

public class Audit {
    public int Id { get; set; }
    public User User { get; set; }
    public DateTime Created { get; set; }
    public string Type { get; set; }
    public int EntityId { get; set; }
    public string Message { get; set; }
}

我有一个DbSet,比如用户,当我进行插入时,我想创建自动在Audit DbSet中添加一个Audit实体。请考虑以下代码:

//var user = new User();
//user.Created = DateTime.Now;
//user.Username = "testuser";
//user.Password = "testpassword";
//dataContext.Users.Add(user);

var post = new Post();
post.Created = DateTime.Now;
post.Title = "A sample post";
post.Published = true;
post.Body = "Some content goes in here...";

dataContext.Posts.Add(post);

var audit = new Audit();
audit.Created = DateTime.Now;
audit.User = CurrentUser.User; // Currently logged in user
audit.Type = "Post.Add";
audit.EntityId = post.Id;
audit.Message = "New post was created";

dataContext.Audits.Add(audit);

dataContext.SaveChanges();

在这种情况下,将添加审计实体,但“EntityId”属性将设置为0(默认值),而不是创建的用户帖子的标识,即标识值(SCOPE_IDENTITY()/ @@ IDENTITY)。

我想将这两个点保留在一个事务中,而不是将项目拆分为两个事务,即先保留 User Post,然后保持审计第二,因为有可能审计可能会失败。

2 个答案:

答案 0 :(得分:2)

覆盖DbContext.SaveChanges()并查看所有ChangeTracker.Entries()。其中​​(e => e.State!= EntityState.Unchanged)。

以下是我的R& D项目的一个例子:

public override int SaveChanges()
{
    int recordsUpdated = 0;

    var journalEntries = new List<AuditJournal>();

    foreach (var entry in this.ChangeTracker.Entries<ITrackedEntity>().Where(e=>e.State != EntityState.Unchanged))
    {
        AuditJournal journal = new AuditJournal();
        journal.Id = Guid.NewGuid();
        journal.EntityId = entry.Entity.Id.Value;
        journal.EntityType = entry.Entity.EntityType;
        journal.ActionType = entry.State.ToString();
        journal.OccurredOn = DateTime.UtcNow;
        //journal.UserId = CURRENT USER
        //journal.PreviousEntityData = XML SERIALIZATION OF ORIGINAL ENTITTY

        journalEntries.Add(journal);
    }

    using (var scope = new TransactionScope())
    {
        recordsUpdated = base.SaveChanges();

        foreach (var journalEntry in journalEntries)
            this.AuditJournal.Add(journalEntry);

        base.SaveChanges(); //Save journal entries

        scope.Complete();
    }

    return recordsUpdated;
}

//Every entity that needs to be audited has to implement this interface
public interface ITrackedEntity
{
    string EntityType { get; }
    Guid? Id { get; set; }
}

答案 1 :(得分:0)

如果您不介意将Post的可引用引用添加到Audit表中,您可以让EF为您完成工作。删除EntityId属性并添加到Audit:

public Post Post {get; set;}

当你录制事件时:

audit.Post = Post;

EF将插入帖子,获取其ID并在同一事务中为您添加对Audit的引用。我们在自己的AuditEvent模型中做了这个确切的事情,我们对各种类型有几个可以为空的引用,因此对于任何给定的事件,我们都可以链接回相关的对象。