64

原本我相信

context.Configuration.AutoDetectChangesEnabled = false;

将禁用更改跟踪。但不是。目前我需要AsNoTracking()在我所有的 LINQ 查询上使用(对于我的只读层)。是否有禁用 DbContext 跟踪的全局设置?

4

7 回答 7

38

由于这个问题没有用特定的 EF 版本标记,我想提一下,在EF Core中,可以在上下文级别配置行为。

您还可以在上下文实例级别更改默认跟踪行为:

using (var context = new BloggingContext())
{
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

    var blogs = context.Blogs.ToList();
}
于 2016-10-01T17:15:21.520 回答
36

在派生的上下文中简单地公开这样的方法并将其用于查询怎么样:

public IQueryable<T> GetQuery<T>() where T : class {
    return this.Set<T>().AsNoTracking();
}

AsNoTracking无法进行全局设置。您必须为每个查询或每个ObjectSet(不是DbSet)设置它。后一种方法需要使用ObjectContextAPI。

var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var set = objectContext.CreateObjectSet<T>();
set.MergeOption = MergeOption.NoTracking;
// And use set for queries
于 2012-10-04T12:29:35.290 回答
17

EntityFramework.Core 中这很容易。

为此,您可以使用UseQueryTrackingBehavior方法。

代码片段在这里:

services.AddDbContext<DatabaseContext>(options =>
{
    options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
    options.UseSqlServer(databaseSettings.DefaultConnection);
});
于 2020-05-29T21:11:58.523 回答
2

你可以在你的 DbContext 中做这样的事情:

public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
{
    Entry(e.Entity).State = EntityState.Detached;
}

每当一个对象被你的上下文具体化时,它就会被分离并且不再被跟踪。

于 2015-03-16T14:47:37.753 回答
1

更新:这并没有真正起作用。看评论!

当我在 StackOverflow 上搜索时,我讨厌它,答案是:“你不能!” 或“你可以,但前提是你完全改变你曾经打过的每一个电话。”

反思任何人?我希望这将是一个 DbContext 设置。但既然不是,我用反射做了一个。

这个方便的小方法将在 DbSet 类型的所有属性上设置 AsNoTracking。

    private void GloballySetAsNoTracking()
    {
        var dbSetProperties = GetType().GetProperties();
        foreach (PropertyInfo pi in dbSetProperties)
        {
            var obj = pi.GetValue(this, null);
            if (obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(DbSet<>))
            {
                var mi = obj.GetType().GetMethod("AsNoTracking");
                mi.Invoke(obj, null);
            }
        }
    }

将其添加到重载的 DbContext 构造函数中。

    public ActivationDbContext(bool proxyCreationEnabled, bool lazyLoadingEnabled = true, bool asNoTracking = true)
    {
        Configuration.ProxyCreationEnabled = proxyCreationEnabled;
        Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
        if (asNoTracking)
            GloballySetAsNoTracking();
    }

它使用反射,这意味着有人会很快评论这是对性能的影响。但它真的那么受欢迎吗?取决于您的用例。

于 2015-11-25T21:05:31.263 回答
0

如果使用实体框架核心,您还可以在继承 DbContext 的类的构造函数中添加以下代码。

public NPCContext()
        : base()
{
     base.ChangeTracker.AutoDetectChangesEnabled = false;
}

或以下

    public NPCContext(DbContextOptions<NPCContext> options)
        : base(options)
    {
        base.ChangeTracker.AutoDetectChangesEnabled = false;
    }
于 2021-02-23T18:24:57.483 回答
0

在我的情况下,因为我需要整个上下文是只读的而不是读/写。

因此,我对 tt 文件进行了更改,并将所有 DbContext 属性更改为返回 DbQuery 而不是 DbSet,从所有属性中删除了集合,对于获取,我返回了 Model.AsNoTracking()

例如:

public virtual DbQuery<Campaign> Campaigns { get{ return Set<Campaign>().AsNoTracking();} }

我在 tt 模板中这样做的方式是:

public string DbQuery(EntitySet entitySet)
    {
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} virtual DbQuery<{1}> {2} {{ get{{ return Set<{1}>().AsNoTracking();}} }}",
            Accessibility.ForReadOnlyProperty(entitySet),
            _typeMapper.GetTypeName(entitySet.ElementType),
            _code.Escape(entitySet));
    }

于 2017-01-05T00:43:21.350 回答