Entity Framework 6 暂时禁用拦截

Posted

技术标签:

【中文标题】Entity Framework 6 暂时禁用拦截【英文标题】:Entity Framework 6 Disable Interception temporarily 【发布时间】:2017-02-01 16:03:52 【问题描述】:

我正在使用IDbCommandTreeInterceptor 在我的模型上启用软删除。

System.Data.Entity.Infrastructure.Interception.DbInterception.Add(
     new SoftDeleteInterception());

我希望能够暂时禁用拦截器,以便我可以选择一个“已删除”的实体进行审计。

但是,DbInterception 集合似乎是程序集范围的。

有没有什么方法可以创建一个新的DbContext没有拦截? 或者甚至在每次创建时将拦截器添加到DbContext 的方法?

【问题讨论】:

嗨,你知道怎么做吗? @jekcom 不幸的是,没有。我最终不得不对我的上下文进行一些(疯狂的)反思,以从中获得我想要的东西。如果你找到方法,请告诉我。 我实际上解决了它(有点)。将在这里发布答案,可能会有所帮助 【参考方案1】:

我用附加属性扩展了我的数据库上下文类

[DbConfigurationType(typeof(DbConfig))] 
public partial class YourEntitiesDB 

    public bool IgnoreSoftDelete  get; set; 

然后在 TreeCreated(...) 方法中检查此标志,如果为 true,则它不会进一步进入 QueryVisitor

public class SoftDeleteInterceptor : IDbCommandTreeInterceptor

    public SoftDeleteInterceptor()
    

    
    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    
        var db = interceptionContext.DbContexts.FirstOrDefault() as YourEntitiesDB;
        if (db!=null && db.IgnoreSoftDelete)
        
            // Ignore soft delete interseptor (Used in archives)
            return;
        

        if (interceptionContext.OriginalResult.DataSpace == DataSpace.CSpace)
        
            var queryCommand = interceptionContext.Result as DbQueryCommandTree;
            if (queryCommand != null)
            
                var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor());
                interceptionContext.Result = new DbQueryCommandTree(
                    queryCommand.MetadataWorkspace,
                    queryCommand.DataSpace,
                    newQuery);
            

            var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
            if (deleteCommand != null)
            
                var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType);
                if (column != null)
                
                    var setClauses = new List<DbModificationClause>();
                    var table = (EntityType)deleteCommand.Target.VariableType.EdmType;
                    if (table.Properties.Any(p => p.Name == column))
                    
                        setClauses.Add(DbExpressionBuilder.SetClause(
                                DbExpressionBuilder.Property(
                                    DbExpressionBuilder.Variable(deleteCommand.Target.VariableType, deleteCommand.Target.VariableName),
                                    column),
                                DbExpression.FromBoolean(true)));
                    

                    var update = new DbUpdateCommandTree(
                        deleteCommand.MetadataWorkspace,
                        deleteCommand.DataSpace,
                        deleteCommand.Target,
                        deleteCommand.Predicate,
                        setClauses.AsReadOnly(),
                        null);

                    interceptionContext.Result = update;
                
            
        
    

为了使用它,我只需在需要时将标志设置为 true

YuorEntitiesDB DB = new YuorEntitiesDB();
DB.IgnoreSoftDelete = true;
DB.Records.Where(...)

【讨论】:

伙计,我发誓我试过了,但没用,但看起来它解决了问题。谢谢! 更新答案,为此您还需要包括 AsNoTracking() @BlackTigerX 你能解释一下为什么你需要使用 AsNoTracking() 吗?我个人不使用它,它工作正常 我也无法让它工作 - 只有第一次它似乎按预期运行。似乎 TreeCreated 方法仅在第一个查询 pr 上运行。实体类型(然后缓存?)。因此,将 IgnoreSoftDelete 设置为 true 将在第一次查询时起作用,但将属性更改回 false 随后将不起作用。无论是否重新创建实体实例,此行为都是正确的。请详细说明@jekcom,如果你能让它工作......在这种情况下,我一定会遗漏一些东西。 @MichaelH.Pedersen TreeCreated 只有在您枚举查询后才会被访问。例如。如果你做 DB.Records.ToList() 你会看到它正在被访问。如果没有看到代码,我无法为您提供太多帮助。因此,如果您愿意,可以使用无效的代码打开一个新问题,我们会尽力提供帮助

以上是关于Entity Framework 6 暂时禁用拦截的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework Core中的日志记录与拦截器

Entity Framework Core 中的日志记录与拦截器

如何在 Entity Framework 4.3.1 中禁用迁移?

如何在 Entity Framework 4.3.1 中禁用迁移?

根据 ASP.NET Core 和 Entity Framework Core 中的条件禁用 [必需] 属性

微软公布Entity Framework 8.0规划