实体框架的审计追踪 [英] audit trail with entity framework

查看:131
本文介绍了实体框架的审计追踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在每个表(InsertedBy,InsertedDate,UpdatedBy和UpdatedDate)中都有用于审计跟踪的字段,我构建了通过覆盖savechange()来减少冗余的解决方案:

I have fields for audit trail in each table (InsertedBy, InsertedDate, UpdatedBy and UpdatedDate), I build solution to reduce redundant before by override savechange():

public override int SaveChanges()
{
    foreach (var entry in ChangeTracker.Entries().Where(e =>
        e.State == System.Data.Entity.EntityState.Added || e.State == System.Data.Entity.EntityState.Modified))
    {
        Auditing.ApplyAudit(entry, User);
    }
    return base.SaveChanges();
}

public class Auditing
{
    public static void ApplyAudit(DbEntityEntry entityEntry, int User)
    {
        Type type = entityEntry.Entity.GetType();
        if (entityEntry.State.ToString() == "Added")
        {
            if (type.GetProperty("InsertedBy") != null)
            {
                entityEntry.Property("InsertedBy").CurrentValue = User;
            }
            if (type.GetProperty("InsertedDate") != null)
            {
                entityEntry.Property("InsertedDate").CurrentValue = DateTime.Now;
            }
        }
        else if (entityEntry.State.ToString() == "Modified")
        {
            if (type.GetProperty("InsertedBy") != null)
            {
                entityEntry.Property("InsertedBy").IsModified = false;
            }
            if (type.GetProperty("InsertedDate") != null)
            {
                entityEntry.Property("InsertedDate").IsModified = false;
            }
            if (type.GetProperty("UpdatedBy") != null)
            {
                entityEntry.Property("UpdatedBy").CurrentValue = User;
            }
            if (type.GetProperty("UpdatedDate") != null)
            {
                entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;
            }
        }
    }
}

问题是:
在修改或增加内存和性能浪费之前在每个实体内使用反射吗?如果是,是否有最佳做法?
是这是另一个性能更好的代码段,还是只使用反射功能?

the question is: is using reflection within each entity before modified or added waste in memory and performance ? if yes is there is best practice for this ? is this another code snippet better in performance or just use reflection also?

public static void ApplyAudit(DbEntityEntry entityEntry, long User)
{
    if (entityEntry.State.ToString() == "Added")
    {
        entityEntry.Property("InsertedBy").CurrentValue = User;
        entityEntry.Property("InsertedDate").CurrentValue = DateTime.Now;
    }
    else if (entityEntry.State.ToString() == "Modified")
    {
        entityEntry.Property("InsertedBy").IsModified = false;
        entityEntry.Property("InsertedDate").IsModified = false;
        entityEntry.Property("UpdatedBy").CurrentValue = User;
        entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;
    }
}

isentityEntry.Property( InsertedBy)使用反射?

is entityEntry.Property("InsertedBy") uses reflection ?

推荐答案

反射缓慢(缓慢是主观的),如果要避免反射,则需要摆脱这种反射代码如下:

Reflection is slow (slow is subjective) and if you want to avoid it, then you need to get rid of such code as below:

Type type = entityEntry.Entity.GetType();
if (type.GetProperty("InsertedBy") != null)

即使速度并不慢,上面的代码仍然笨拙,因为程序员可能会错误地编写 InsertBy 而不是 InsertedBy 。可以使用以下方法在编译器的帮助下轻松避免这种情况。

Even if it was not slow, the code above is still "buggy" because a programmer may mistakenly write InsertBy instead of InsertedBy. This can easily be avoided with help from the compiler using the approach below.

使用接口并在需要审计的所有实体中实施该接口。

Use an interface and implement it in all entities that require audit.

public interface IAuditable
{
    string InsertedBy { get; set; }
    // ... other properties
}

public class SomeEntity : IAuditable
{
    public string InsertedBy { get; set; }
}

public class Auditor<TAuditable> where TAuditable : IAuditable
{
    public void ApplyAudit(TAuditable entity, int userId)
    {
        // No reflection and you get compiler support
        if (entity.InsertedBy == null)
        {
            // whatever
        }
        else
        {
            // whatever
        }
    }
}

如评论中所述,您将获得编译器支持,并且不再使用反射。我什至会更进一步,并且不会传递 int userId 。我将带出用于弄清 userId 的代码,并将其放在此类中。这样,班级就足够了,客户无需向其提供此信息。

As mentioned in the comments, you will get compiler support and reflection is not used anymore. I would even go a step further and not pass the int userId. I will bring the code for figuring out the userId and put it in this class. That way the class is self sufficient and clients do not need to provide it this information.

用法:

var e = new SomeEntity();
var auditor = new Auditor<SomeEntity>();
auditor.ApplyAudit(e, 1); // 1 is userId, I am just hardcoding for brevity

进行硬编码,或者从您的上下文中使用它:

Or use it from your context:

public override int SaveChanges()
{
    var auditables = ChangeTracker.Entries().Where(e =>
        e.State == System.Data.Entity.EntityState.Added || e.State == System.Data.Entity.EntityState.Modified)
        .OfType<IAuditable>();
    var auditor = new Auditor<IAuditable>();
    foreach (var entry in auditables)
    {
        // 1 is userId, I am just hardcoding for brevity
        auditor.ApplyAudit(entry, 1);
    }
    return base.SaveChanges();
}

这意味着所有可审核的实体都需要实施 IAuditable 接口。 EF会为您的实体生成部分类,但是不会修改这些部分类,因为下次您运行自定义工具时,它将被清除。

This means that all entities who are auditable will need to implement the IAuditable interface. EF generates partial classes for your entities but do not modify those partial classes because the next time you run the custom tool, it will be wiped out.

相反,创建另一个部分类具有相同名称的类并实现 IAuditable

Instead, create another partial class with the same name and implement the IAuditable.

public partial class SomeEntity : IAuditable {}

一种更好的方法是创建自定义T4模板,以便它创建部分代码为的类:IAuditable 。请参阅此文章以了解操作方法。

An even better approach is to create a custom T4 template so it creates the partial class with the code : IAuditable. Please see this article for how to do that.

这篇关于实体框架的审计追踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆