审计跟踪与实体框架

时间:2018-03-09 21:44:09

标签: c# entity-framework

我在每个表中都有审计跟踪的字段(InsertedBy,InsertedDate,UpdatedBy和UpdatedDate),我通过覆盖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;
            }
        }
    }
}

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

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;
    }
}

是entityEntry.Property(“InsertedBy”)使用反射?

1 个答案:

答案 0 :(得分:3)

反射很慢(慢是主观的)如果你想避免它,那么你需要摆脱下面的代码:

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

即使它不慢,上面的代码仍然是" buggy"因为程序员可能会错误地写InsertBy而不是InsertedBy。在编译器的帮助下使用下面的方法可以很容易地避免这种情况。

使用界面并在需要审核的所有实体中实施。

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的代码并将其放入此类中。这样,这个课程就足够了,客户不需要提供这些信息。

用法:

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

或者从您的上下文中使用它:

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为您的实体生成部分类,但不修改这些部分类,因为下次运行自定义工具时,它将被清除。

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

public partial class SomeEntity : IAuditable {}

更好的方法是创建自定义T4模板,以便创建代码为: IAuditable的分部类。有关如何操作的信息,请参阅this article