zoukankan      html  css  js  c++  java
  • EF Core – QueryFilter & Interception

    主要参考

    Global Query Filters

    Interceptors

    QueryFilter

    QueryFilter 就是默认过滤, 非常适合用来做 Soft Delete

    builder.HasQueryFilter(e => EF.Property<DateTimeOffset?>(e, "DateDeleted") == null);

    设置这个以后, 一般的 query 语句就拿不到 deleted 的 row 了

    如果想获取 deleted row 那么就需要通过 IgnoreQueryFilters 来 by pass 它.

    blogs = db.Blogs
        .Include(b => b.Posts)
        .IgnoreQueryFilters()
        .ToList();

    Interception

    Interception 也适合用来做 Soft Delete 或者简单的 Audit Trail

    但是还有一个更简单的做法是直接 override SaveChangesAsync 方法

    去 DbContext class

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        foreach (var entry in ChangeTracker.Entries())
        {
            if (entry.State == EntityState.Added)
            {
                        
            }
            else if (entry.State == EntityState.Modified)
            {
    
            }
            else if (entry.State == EntityState.Deleted)
            {
    
            }
            var tableName = entry.Metadata.GetTableName();
    
            foreach (var property in entry.Properties)
            {
                var isModified = property.IsModified;
                var originalValue = property.OriginalValue;
                var currentValue = property.CurrentValue;
                var metadata = property.Metadata;
            }
        }
        return base.SaveChangesAsync(cancellationToken);
    }

    获取 Entry 资料, 然后修改 Entry 就可以操控最终 save 的结构了. (比如把 Deleted 换成 Modified)

    创建一个 Interceptor (我这里用 SaveChangesInterceptor 举例)

    public class SoftDeleteInterception : SaveChangesInterceptor
    {
        public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
        {
            var entities = eventData.Context!.ChangeTracker.Entries();
            return new ValueTask<InterceptionResult<int>>(result);
        }
    }

    注: SavingChangesAsync 是 before SQL, SavedChangesAsync 是 after success SQL, FailedChangesAsync 是 after fail SQL.

    在 DbContext class register 这个 interceptor

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.AddInterceptors(new SoftDeleteInterception());

    Change State in SaveChanges

    看注释, 有些逻辑和平时会不同,比如 set value 时, 不会 update IsModified (但 generate 出来的语句还是有的, 我想可能 EF 最后还会再对比一次吧...懒惰去研究了)

    foreach (var entry in eventData.Context!.ChangeTracker.Entries())
    {
        var entityType = entry.Entity.GetType();
        if (entityType.FullName == "TestEFCore.Product")
        {
            entry.State = EntityState.Unchanged; // if change to modified then all properties will become IsModified 
            typeof(Product).GetProperty("Name")!.SetValue(entry.Entity, "New Value"); // current value 会 update, but IsModified 依然是 false
            entry.Property("DateDeleted").CurrentValue = DateTimeOffset.Now;
            entry.Property("DateDeleted").IsModified = true; // will update entry.State to modified
            foreach (var p in entry.Properties)
            {
                var isModified = p.IsModified;
            }
            var state = entry.State;
        }
    }

    Dependency Injection inside Interceptor

    参考:

    Ability to register IInterceptor without an IDbContextOptionsExtension

    A better way of resolving EF Core interceptors with dependency injection

  • 相关阅读:
    4-18
    Vue学习 2017-4-9
    前端杂谈
    不错的博客哦!
    待整理知识杂项
    Vue学习历程
    王工的权限理解
    【NX二次开发】图标图像
    【转】C++怎么读写windows剪贴板的内容?比如说自动把一个字符串复制.
    获取计算机名
  • 原文地址:https://www.cnblogs.com/keatkeat/p/15427088.html
Copyright © 2011-2022 走看看