解决ASP.NET Boilerplate与EntityFramework反复出现无用更新的现象[Update]

作者:V君 发布于:2016-10-23 15:49 Sunday 分类:挖坑经验

TL;DR

重写SaveChanges和SaveChangesAsync ,

在base实现调用之前增加以下代码,去除对前三个字段的无用更新的操作.

private static readonly HashSet<string> IgnoreCheckUpdateFields = new HashSet<string>

{

    nameof(IAudited.CreationTime),

    nameof(IAudited.LastModificationTime),

    nameof(IAudited.LastModifierUserId),

    nameof(Entity.Id),

};


private void BlockNeedLessUpdate()

{

    //LEVEL 1: always CreationTime

    var allModified = ChangeTracker

        .Entries<ICreationAudited>()

        .Where(p => p.State == EntityState.Modified);


    foreach (var item in allModified)

        item.Property(nameof(ICreationAudited.CreationTime))

            .IsModified = false;


    //LEVEL 2: only LastModificationTime LastModifierUserId

    var allModified2 = ChangeTracker

        .Entries<IAudited>()

        .Where(p => p.State == EntityState.Modified);


    foreach (var item in allModified2)

    {

        var changed = item.CurrentValues.PropertyNames

         .Any(p => !IgnoreCheckUpdateFields.Contains(p) 

         && false == item.CurrentValues[p]?.Equals(item.OriginalValues[p]));


        if (changed) continue;

        item.Property(nameof(IAudited.LastModificationTime)).IsModified = false;

        item.Property(nameof(IAudited.LastModifierUserId)).IsModified = false;

    }

}

 

听我扯扯:

由于ASP.NET Boilerplate首次启动/登录时很慢, 于是将EF生成的SQL语句打到调试输出.

发现大量的创建时间被更新的现象. 

深入调查发现可能是因为 CreationAuditedEntity 在构造时初始化成 Clock.Now

然后EF从数据库读出值再次绑定,

造成 CreationTime 的 setter 被多次调用导致变更追踪机制懵逼.

粗暴地把所有对 CreationTime 的更新操作屏蔽就好了.

不知道是不是错觉, 这么做了之后发现调试启动速度快了70%呀.


ps. 或许 EF 的变更追踪没有 dbml 那么完善,它只监视赋值行为.然而 dbml 还检查了值变化.


Update:

随着继续调试又发现Tenant的LastModificationTime和LastModifierUserId被更新

然而并没更新到别的字段, 明显这样的更新动作是无用的.

进一步调试看起来EF只是简单的比较了两个装了箱的值, 然而在SQL层面又做了值重复过滤

导致这种尴尬现象.

标签: 软件开发 C# 数据库

引用地址:

发表评论:

Powered by emlog 去你妹的备案 sitemap