我使用EF5和CodeFirst构建了一个applciation。在运行时,我的应用程序创建一个LocalDB数据库文件和一个DataContext的类级实例。一切正常,但是大约50,000条记录(约20MB MDF文件)后插入速度很慢。在调试中,我可以看到内部Connection的状态设置为'Closed'。我假设EF5在每次插入后关闭连接,然后在需要时重新打开它。
如何阻止Entity Framework关闭连接?这是一个本地,可能需要在最短的时间内导入多达500k的记录。
查看连接状态显示频繁更改。左边的字符串是yyyyMMddHHmmssfff格式的日期戳...
这些只是来自同一个ONE SECOND的小片段。这必须是[至少]慢速插入的一部分。
答案 0 :(得分:1)
您的问题与打开和关闭连接无关。你似乎已经得出了错误的结论,并且正在竞相解决错误的问题。事实上,LocalDb没有连接,因为它是一个基于本地文件的数据库。
您的问题是您有类级数据上下文。实体框架数据上下文的设计是短暂的。他们没有真正的资源管理,他们认为一旦交易完成,你将处置并销毁它。
当你在每次事务之后不破坏数据上下文时,随着上下文不断变大,分配和重新分配内存,你在一段时间后变慢的问题很常见。随着上下文变大,每次调用SaveChanges时,EF必须遍历本地缓存中的记录列表,并且随着越来越多的记录被插入,这需要更长更长的时间。
我建议你重新考虑一下你的设计。您有几个选项,第一个选项就是按照我的建议完成,并在每次交易后销毁上下文。第二种方法是,如果您只是使用context.Database.ExecuteSqlCommand()
进行插入并使用直接sql命令,或者甚至更好,请完全绕过该模型,而是使用Sql Bulk插入。
答案 1 :(得分:0)
很可能你会保持周围的对象和膨胀。您可以通过使用任务管理器并观察内存使用情况来证明这一点。它的规模可能会越来越大。
如果您不再需要这些对象,请在完成后立即从上下文中删除它们。您可以使用存储库轻松完成此操作。
首先,将它们分开的代码......
GenericRepository<Path> repo = new GenericRepository<Path>(context);
repo.Detach(item);
接下来,通用存储库......
public class GenericRepository<T> : IRepository<T>
where T : class
{
protected DbSet<T> DbSet { get; set; }
protected DbContext Context { get; set; }
public GenericRepository(DbContext context)
{
if (context == null)
{
throw new ArgumentException("An instance of DbContext is " +
"required to use this repository.", "context");
}
this.Context = context;
this.DbSet = this.Context.Set<T>();
}
public IQueryable<T> GetAll()
{
return this.DbSet;
}
public T GetById(int id)
{
return this.DbSet.Find(id);
}
public void Add(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Detached)
{
entry.State = EntityState.Added;
}
else
{
this.DbSet.Add(entity);
}
}
public void Update(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State == EntityState.Detached)
{
this.DbSet.Attach(entity);
}
entry.State = EntityState.Modified;
}
public void Delete(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Deleted)
{
entry.State = EntityState.Deleted;
}
else
{
this.DbSet.Attach(entity);
this.DbSet.Remove(entity);
}
}
public void Delete(int id)
{
var entity = this.GetById(id);
if (entity != null)
{
this.Delete(entity);
}
}
public void Detach(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
entry.State = EntityState.Detached;
}
}
我希望这会有所帮助。