你可以从一个DbSet中的DbContext?
在我的申请,有时必须至10,000或更多的行保存到数据库中在一个操作中。我发现,简单地迭代,并在同一时间将每个项目可以采取半小时以上。
In my application it is sometimes necessary to save 10,000 or more rows to the database in one operation. I've found that simply iterating and adding each item one at a time can take upwards of half an hour.
不过,如果我禁用AutoDetectChangesEnabled需要约5秒(这正是我想要的)
However, if I disable AutoDetectChangesEnabled it takes ~ 5 seconds (which is exactly what I want)
我试图使被称为的AddRange来DbSet扩展方法,这将禁用AutoDetectChangesEnabled,然后重新启用它完成时。
I'm trying to make an extension method called "AddRange" to DbSet which will disable AutoDetectChangesEnabled and then re-enable it upon completion.
public static void AddRange<TEntity>(this DbSet<TEntity> set, DbContext con, IEnumerable<TEntity> items) where TEntity : class
{
// Disable auto detect changes for speed
var detectChanges = con.Configuration.AutoDetectChangesEnabled;
try
{
con.Configuration.AutoDetectChangesEnabled = false;
foreach (var item in items)
{
set.Add(item);
}
}
finally
{
con.Configuration.AutoDetectChangesEnabled = detectChanges;
}
}
所以,我的问题是:有没有办法从一个DbSet中的DbContext?我不喜欢使其成为一个参数 - 这感觉就像它应该是不必要的。
So, my question is: Is there a way to get the DbContext from a DbSet? I don't like making it a parameter - It feels like it should be unnecessary.
是,您可以从 DbSet<获得
,但解决的办法是反射沉重。我已经提供了如何做到这一点下面的例子。的DbContext
; TEntity>
Yes, you can get the DbContext
from a DbSet<TEntity>
, but the solution is reflection heavy. I have provided an example of how to do this below.
我测试下面的代码,它能够成功地检索的DbContext
实例,从中 DbSet 。请注意,虽然它不回答你的问题,有几乎可以肯定是一个更好的解决您的问题
I tested the following code and it was able to successfully retrieve the DbContext
instance from which the DbSet
was generated. Please note that, although it does answer your question, there is almost certainly a better solution to your problem.
public static class HackyDbSetGetContextTrick
{
public static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity: class
{
object internalSet = dbSet
.GetType()
.GetField("_internalSet",BindingFlags.NonPublic|BindingFlags.Instance)
.GetValue(dbSet);
object internalContext = internalSet
.GetType()
.BaseType
.GetField("_internalContext",BindingFlags.NonPublic|BindingFlags.Instance)
.GetValue(internalSet);
return (DbContext)internalContext
.GetType()
.GetProperty("Owner",BindingFlags.Instance|BindingFlags.Public)
.GetValue(internalContext,null);
}
}
实例:
Example usage:
using(var originalContextReference = new MyContext())
{
DbSet<MyObject> set = originalContextReference.Set<MyObject>();
DbContext retrievedContextReference = set.GetContext();
Debug.Assert(ReferenceEquals(retrievedContextReference,originalContextReference));
}
说明:
据反射, DbSet< TEntity>
有一个私有字段 _internalSet
类型 InternalSet< TEntity> 。类型是内部的的EntityFramework DLL。从 InternalQuery<继承; TElement>
(其中 TEntity:TElement
)。 InternalQuery< TElement>
也是内部的DLL的EntityFramework。它有一个私有字段 _internalContext
键入 InternalContext
的。 InternalContext
也是内部的EntityFramework。然而, InternalContext
公开叫所有者
公共的DbContext
属性。所以,如果你有一个 DbSet< TEntity>
,你可以在的DbContext
业主参考,通过访问各这些特性沉思和铸造的最终结果为的DbContext
。
According to Reflector, DbSet<TEntity>
has a private field _internalSet
of type InternalSet<TEntity>
. The type is internal to the EntityFramework dll. It inherits from InternalQuery<TElement>
(where TEntity : TElement
). InternalQuery<TElement>
is also internal to the EntityFramework dll. It has a private field _internalContext
of type InternalContext
. InternalContext
is also internal to EntityFramework. However, InternalContext
exposes a public DbContext
property called Owner
. So, if you have a DbSet<TEntity>
, you can get a reference to the DbContext
owner, by accessing each of those properties reflectively and casting the final result to DbContext
.
在EF7有一个私有字段_context直接在类的工具DbSet。不难公开揭露这一领域
In EF7 there is a private field _context directly in the class the implements DbSet. It's not hard to expose this field publicly