【问题标题】:Injecting changes to model data将更改注入模型数据
【发布时间】:2023-04-09 17:21:01
【问题描述】:

我的某些实体具有 LastUpdated 和 LastUpdatedBy 等审计跟踪元素。我正在寻找最合适的方法,以便在模型更改时将这些字段更新为当前日期和时间以及当前用户。

最简单的实现是在我更​​新 objectcontext 之前影响我的控制器中的这个更改,但这会导致大量重复代码。我可以稍微重构一下,并可能创建一个辅助方法,我也可以调用和传递模型,从而将事情减少到控制器中的一行代码,但老实说,我宁愿这是自动的,控制器代码不必担心关于。

以前有人处理过这个问题吗?你的解决方案是什么?你有什么建议?

(ps mvc 和 ef noob 所以我可能缺少一个框架类型选项)

【问题讨论】:

  • 敬请期待,我在没有 T4 的情况下通过挂钩新的可覆盖 SaveChanges 事件来完成此操作。

标签: c# asp.net-mvc entity-framework asp.net-mvc-2


【解决方案1】:

我遵循与@Nix 类似的模式,只是我没有使用 T4,因为我更喜欢代码优先开发而不是设计器。如果您有一个名为MyDbContextContext,您可以对它进行部分分类以覆盖SaveChanges() 方法。我还有一个 IAuditable 类,我所有必要的实体都从它扩展而来。

public interface IAuditable
{
    User CreatedBy { get; set; }
    DateTime? DateCreated { get; set; }
    User ModifiedBy { get; set; }
    DateTime? DateModified { get; set; }
    User DeletedBy { get; set; }
    DateTime? DateDeleted { get; set; }
}

// Classes that implement the IAuditable here.

public class User : EntityObject
{
    public string Username { get; set; }
    public string DisplayName { get; set; }
    // etc...
}

partial class MyDbModel
{
    public override int SaveChanges(SaveOptions options)
    {

        // Search all added, modified or deleted entities.
        var entries = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);

        foreach (var entry in entries)
        {

            var auditable = entry.Entity as IAuditable;

            if (auditable != null)
            {
                if (entry.State == EntityState.Added)
                {
                    auditable.CreatedBy = null; // TODO - Get current user.
                    auditable.DateCreated = DateTime.Now;
                    auditable.ModifiedBy = null; // TODO - Same as CreatedBy?
                    auditable.DateModified = DateTime.Now;
                }
                else if (entry.State == EntityState.Modified)
                {
                    auditable.ModifiedBy = null; // TODO - Get current user.
                    auditable.DateModified = DateTime.Now;
                }
                else if (entry.State == EntityState.Deleted)
                {
                    auditable.DeletedBy = null; // TODO - Get current user.
                    auditable.DateDeleted = DateTime.Now;
                }
            }
        }


        return base.SaveChanges(options);
    }
}

【讨论】:

  • 我将发布相同的代码,但我更喜欢反射而不是实现接口。
  • @jfar - 我不走反射路线的唯一原因是性能影响。
  • 性能影响可以忽略不计。反射没有那么慢。 1000 次迭代测试:反射:12 毫秒,原生:2 毫秒。没有大碍。我估计一个大型工作单元一次会更新 10 个实体,反射 1 毫秒,原生 0 毫秒。我相信你的用户不会关心 1ms。
  • @jfar - 这真的取决于反射的情况。我创建了一个 IoC 容器,其中使用原始 Activator.CreateInstanceILGenerator.Emitway 创建一个类型的实例。对于这种情况,我每秒处理很多请求,所以对我来说毫秒数很重要。此外,我认为当其他人查看代码时,使用该界面可以让事情变得更清晰。同样,这真的取决于情况。
【解决方案2】:

我做过这样的事情,我使用了 T4 模板。见:Entity Framework Trigger Like Auditing

基本上我只是让所有实体扩展一个接口,然后在 SaveChanges 中遍历所有“IAuditable”并设置更新/插入日期。

对我们来说工作得很好,但我们也经历了,并且为每个实体确保审计字段具有相同的名称。一旦你这样做了,就很容易为那些包含审计字段的表自动生成自定义代码。感谢有意义吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 2014-04-05
    • 2015-12-14
    • 2019-07-20
    • 1970-01-01
    • 2017-08-24
    • 2013-07-02
    • 2015-11-13
    相关资源
    最近更新 更多