2013-08-18 95 views
1

我使用EF5和CodeFirst构建了一个应用程序。在运行时,我的应用程序创建一个LocalDB数据库文件和一个DataContext的类级实例。一切正常,但大约50,000条记录(大约20MB的MDF文件)后插入缓慢。在调试中,我可以看到内部Connection的状态设置为'Closed'。我假设EF5在每次插入后关闭连接,然后在需要时重新打开连接。如何防止EF5 LocalDB连接关闭

如何防止Entity Framework关闭连接?这是一个本地可能需要在最短的时间内导入多达50万条记录的地方。

查看连接状态会显示频繁更改。该字符串的左边是yyyyMMddHHmmssfff格式的日期戳...

  • 20130818072134139:原文:打开/电流:关闭
  • 20130818072134160:原文:关闭/电流:打开
  • 20130818072134163:原文:打开/电流:关闭
  • 20130818072134185:原文:关闭/电流:打开
  • 20130818072134188:原文:打开/电流:关闭
  • 20130818072134209:原文:关闭/电流:打开
  • 20130818072134212:原文:打开/电流:关闭
  • 20130818072134246:原文:关闭/电流:打开

这些都是从同一个一秒钟只是一个小片段。这必须是[至少]缓慢插入的一部分。

+0

如果你有更多的细节,你可以请编辑你的问题,它真的很难在评论中阅读 –

回答

1

您的问题与打开和关闭连接无关。你似乎已经跳到了错误的结论,并在争分夺秒地解决错误的问题。实际上,LocalDb没有连接,因为它是基于本地文件的数据库。

你的问题是你有一个类级别的数据上下文。实体框架数据上下文被设计为短暂的。他们没有真正的资源管理,他们认为一旦交易完成,你将处置并销毁它。

随着上下文越来越大,以及分配和重新分配内存,在每次事务之后不要销毁数据上下文时,常常会遇到一段时间后变慢的问题。随着上下文变大,每次调用SaveChanges时,EF都必须遍历本地缓存中的记录列表,并且随着越来越多的记录被插入,这需要越来越长的时间。

我建议你重新考虑一下你的设计。你有几种选择,第一种是按照我的建议简单地做,并在每次交易后销毁上下文。第二种方法是完全绕过模型,如果只是简单地插入并使用使用context.Database.ExecuteSqlCommand()或甚至更好的直接sql命令,则改为使用Sql Bulk插入。

0

很可能是你保持周围的对象和膨胀的上下文。您可以通过使用任务管理器并观察内存使用情况来证明这一点。它的规模可能会越来越大。

如果您不再需要这些对象,那么在您通过时立即将它们从上下文中分离出来。你可以使用Repository来很容易地完成这个任务。

首先,代码脱离他们...

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; 
    } 
} 

我希望这有助于。

+0

真棒!谢谢!我把我的时间减少了近100%!今天早上,500k条记录在虚拟机上花费了大约10个小时。包括上面的代码后,花了大约5分钟! =) –