本来我认为AsNoTracking()的全局设置?
context.Configuration.AutoDetectChangesEnabled = false;
将禁用更改跟踪。但不是。目前我需要在我所有的LINQ查询中使用AsNoTracking()
(对于我的只读图层)。是否有全局设置禁用DbContext上的跟踪?
本来我认为AsNoTracking()的全局设置?
context.Configuration.AutoDetectChangesEnabled = false;
将禁用更改跟踪。但不是。目前我需要在我所有的LINQ查询中使用AsNoTracking()
(对于我的只读图层)。是否有全局设置禁用DbContext上的跟踪?
由于此问题未使用特定的EF版本进行标记,因此我想提及在EF Core中的行为可能是configured at the context level。
您也可以在上下文 实例级别更改默认跟踪行为:
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
什么根本上派生的背景下暴露的方法像这样利用它进行查询:
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
你可以做这样的事情在你的DbContext:
public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
{
Entry(e.Entity).State = EntityState.Detached;
}
每当一个对象被你的情况下实现,它将被分离并不再跟踪。
我认为这可行,但也许不是最好的方式来做到这一点。 AsNoTracking()据我所知不附加和分离对象。 –
这里的答案阐述了两者之间的区别。 http://stackoverflow.com/a/20163424/219072这听起来像AsNoTracking()绝对是首选的方法。 – emragins
更新:这并没有真正的工作。看评论!
我讨厌它,当我在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();
}
它使用反射,这意味着有人会很快评论这是一个性能问题。但是,这真的是一个打击?取决于你的用例。
我还没有测试过,但据我所知,'AsNoTracking()'只返回当前设置为未跟踪的'IQueryable'。在'DbSet'上调用它不会使下一个查询未被跟踪。我从这段代码中得到的理解是,你在所有的集合上都调用了'AsNoTracking()',但是除非你使用返回的可查询任何东西 – Jcl
@Jcl,否则它不会做任何事情,我必须检查它。它似乎在为我工作。 – Rhyous
我现在没有时间来测试它,但乍一看对我来说很可疑。如果这样做的话,这意味着只要你在上下文中的'DbSet'上调用'AsNoTracking()',那么在同一个上下文中'DbSet'上的所有后续查询都将不被跟踪......而那个是一些奇怪的行为(特别是考虑到没有'AsTracking()'来补偿)。如果这确实有效,我会说这是一个错误...或无证的功能:-) – Jcl
在我来说,因为我需要的整个来龙去脉是只读的,而不是读/写。
所以我做了tt文件的更改,并更改了所有DbContext属性以返回DbQuery而不是DbSet,从所有属性中删除了这些集合,并且为get而返回了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));
}
你的链接告诉我错误 –
@AliYousefie谢谢你,我修正了这个问题。 –