簡體   English   中英

AsNoTracking() 的全局設置?

[英]Global setting for AsNoTracking()?

原本我相信

context.Configuration.AutoDetectChangesEnabled = false;

將禁用更改跟蹤。 但不是。 目前我需要在我的所有 LINQ 查詢(對於我的只讀層)上使用AsNoTracking() )。 是否有禁用 DbContext 跟蹤的全局設置?

簡單地在派生上下文中公開這樣的方法並將其用於查詢怎么樣:

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

AsNoTracking全局設置AsNoTracking 您必須為每個查詢或每個ObjectSet (不是DbSet )設置它。 后一種方法需要使用ObjectContext API。

var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var set = objectContext.CreateObjectSet<T>();
set.MergeOption = MergeOption.NoTracking;
// And use set for queries

由於這個問題沒有用特定的 EF 版本標記,我想提一下,在EF Core 中,可以在上下文級別配置行為。

您還可以在上下文實例級別更改默認跟蹤行為:

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

    var blogs = context.Blogs.ToList();
}

EntityFramework.Core 中,這很容易。

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

代碼片段在這里:

services.AddDbContext<DatabaseContext>(options =>
{
    options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
    options.UseSqlServer(databaseSettings.DefaultConnection);
});

你可以在你的 DbContext 中做這樣的事情:

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

每當一個對象被你的上下文物化時,它就會被分離並且不再被跟蹤。

更新:這並沒有真正奏效。 看評論!

當我在 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();
    }

它使用反射,這意味着有人會很快評論說這是性能下降。 但它真的那么受歡迎嗎? 取決於您的用例。

就我而言,因為我需要將整個上下文設為只讀而不是讀/寫。

因此,我對 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)); }

如果使用實體框架核心,您還可以在繼承 DbContext 的類的構造函數中添加以下代碼。

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

或以下

    public NPCContext(DbContextOptions<NPCContext> options)
        : base(options)
    {
        base.ChangeTracker.AutoDetectChangesEnabled = false;
    }

您可以使用以下代碼片段作為參考

optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

請注意,在 EF Core 5.0 之前,無法使用“無跟蹤”啟用身份解析。 但是現在,使用 EF Core 5.0,可以使用額外的 API 來啟用“無跟蹤”和身份解析。 因此,如果您想通過身份解析“不跟蹤”,那么在 EF Core 5.0 中使用以下代碼段

optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTrackingWithIdentityResolution);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM