1

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

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

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

  • 20130818072134139:原始:打开/当前:关闭
  • 20130818072134160:原始:关闭/当前:打开
  • 20130818072134163:原始:打开/当前:关闭
  • 20130818072134185:原始:关闭/当前:打开
  • 20130818072134188:原始:打开/当前:关闭
  • 20130818072134209:原始:关闭/当前:打开
  • 20130818072134212:原始:打开/当前:关闭
  • 20130818072134246:原始:关闭/当前:打开

这些只是同一个 ONE SECOND 的一小部分。这必须是 [至少] 慢速插入的一部分。

4

2 回答 2

1

您的问题与打开和关闭连接无关。你似乎跳到了错误的结论,并且正在竞相解决错误的问题。事实上,LocalDb 没有连接,因为它是基于本地文件的数据库。

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

当您在每次事务后不破坏数据上下文时,一段时间后变慢的问题很常见,因为上下文不断增长,并且分配和重新分配内存。随着上下文变大,每次调用 SaveChanges 时,EF 都必须遍历本地缓存中的记录列表,并且随着插入的记录越来越多,这需要的时间越来越长。

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

于 2013-08-18T20:26:28.807 回答
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;
    }
}

我希望这有帮助。

于 2013-08-18T21:47:51.287 回答