.net AsNoTracking()的全局设置?

ljo96ir5  于 2023-03-31  发布在  .NET
关注(0)|答案(8)|浏览(174)

起初我相信

context.Configuration.AutoDetectChangesEnabled = false;

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

prdp8dxp

prdp8dxp1#

由于这个问题没有标记特定的EF版本,我想提到的是,在 EF Core 中,行为可以是configured at the context level
您还可以在上下文示例级别更改默认跟踪行为:

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

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

mf98qq942#

那么简单地在你的派生上下文中暴露这样的方法并将其用于查询呢:

public IQueryable<T> GetQuery<T>() where T : class {
    return this.Set<T>().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
b5buobof

b5buobof3#

EntityFramework.Core中,这非常简单。
为此,您可以使用UseQueryTrackingBehavior方法。
代码片段在这里:

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

4c8rllxm4#

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

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

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

fivyi3re

fivyi3re5#

在我的例子中,因为我需要整个上下文是只读的,而不是读/写的。
所以我对tt文件做了一个更改,并将所有DbContext属性更改为返回DbQuery而不是DbSet,从所有属性中删除了集合,对于gets,我返回了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));
    }
2izufjch

2izufjch6#

更新:这并没有真正的工作.查看评论!
反射有人吗?我希望这将是一个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();
    }

它使用反射,这意味着有人会很快评论说这是一个性能打击。但是它真的有那么大的打击吗?取决于你的用例。

k2fxgqgv

k2fxgqgv7#

您可以使用下面的代码片段作为参考

optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

在这里请注意,在EF Core 5.0之前,没有办法启用身份解析与“无跟踪”.但现在,与EF Core 5.0,一个额外的API可以用来启用“无跟踪”和身份解析.所以,如果你想“无跟踪”与身份解析,然后在EF Core 5.0使用下面的片段

optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTrackingWithIdentityResolution);
quhf5bfb

quhf5bfb8#

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

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

或以下

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

相关问题