EntityFramework通用存储库模式,OutOfMemoryException

时间:2013-12-25 00:48:54

标签: c# entity-framework out-of-memory repository-pattern

我看到一种非常奇怪的行为,我花了两天的时间试图弄清楚发生了什么。任何帮助表示赞赏。

所有问题。我正在使用实体框架禁令和存储库模式。如果我没有指定DbContext的具体类型,我将获得OutOfMemoryExpecption。但是,指定具体类型确实破坏了我试图实现的通用模式。有谁知道为什么会发生这种情况,ConcreteDbContext.Models和DbContext.Set之间的区别是什么?

注意:我正在处理一个大约200万个recrods的数据集。

OutOfMemoryException场景

public interface IRepository<T> where T : class
{
    T Add(T entity);
    T Update(T entity);
    T Delete(T entity);
    IEnumerable<T> GetAll();
    ...
}

  public class MyDbContext : DbContext
{
    public MyDbContext (string connectionString)
        : base(connectionString)
    {
          //Intentionally Left Blank
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual IDbSet<MyModel> Models{ get; set; }
}



 public abstract class EfRepositoryBase<T> : IRepository<T>
    where T : class

{
     private readonly DbSet<T> _dbSet;

     protected EfRepositoryBase(DbContext context)
    {
        _dbSet = context.Set<T>();
    }

     protected IDbSet<T> Table
    {
        get { return _dbSet; }
    }
  ...
 }


public class MyRepository : EfRepositoryBase<MyModel>, IMyRepository
{

    public MyRepository (DbContext context)
        : base(context)
    {
    }

    //Example Method
    public IList<DateTime> DoStuff(DateTime start, int lookforward)
    {
        var startRangeEnd = start.AddDays(lookforward);
        var startRange =
            Table.AsNoTracking()
                   .Where(s => s.eventDate >= start && s.eventDate <= startRangeEnd)
                   .OrderBy(o => o.eventDate)
                   .Select(s => s.eventDate).Distinct();
        return startRange.ToList();
    }

   .... //More methods that do Linq Queries
 }

工作场景 请注意,在工作场景中我需要在我的EfBaseRepository中返回Context然后在我的实现中将其转换为具体类型以访问Models Dbset 。 (我也可以在EFBaseRepository中返回MyDbContext,但我试图避免使用具体的MyDbContext类型。)

public interface IRepository<T> where T : class
{
    T Add(T entity);
    T Update(T entity);
    T Delete(T entity);
    IEnumerable<T> GetAll();
    ...
}

  public class MyDbContext : DbContext
{
    public MyDbContext (string connectionString)
        : base(connectionString)
    {
          //Intentionally Left Blank
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual IDbSet<MyModel> Models{ get; set; }
}



 public abstract class EfRepositoryBase<T> : IRepository<T>
    where T : class

{
     private readonly DbSet<T> _dbSet;
     private readonly DbContext _dbContext;

     protected EfRepositoryBase(DbContext context)
    {
        _dbSet = context.Set<T>();
    }

     protected DbContext Table
    {
        get { return _dbContext; }
    }
  ...
 }


public class MyRepository : EfRepositoryBase<MyModel>, IMyRepository
{

    public MyRepository (DbContext context)
        : base(context)
    {
    }

    protected MyDbContext Ctx
     { get { return Table as MyDbContext; } }

    //Example Method
    public IList<DateTime> DoStuff(DateTime start, int lookforward)
    {
        var startRangeEnd = start.AddDays(lookforward);
        var startRange =
            Ctx.Models.AsNoTracking()
                   .Where(s => s.eventDate >= start && s.eventDate <= startRangeEnd)
                   .OrderBy(o => o.eventDate)
                   .Select(s => s.eventDate).Distinct();
        return startRange.ToList();
    }

   .... //More methods that do Linq Queries
 }

1 个答案:

答案 0 :(得分:1)

这是Unbounded result set的正常行为。无界结果集是查询未明确限制查询返回结果数的位置。 more info here

要解决此问题,您需要使用TakeSkip方法开始分页结果:

const int pageSize = 25;
var list = ctx.Table1.OrderBy(g => g.Id)
        .Select(g => ....)
    .Skip(pageSize * pageNumber)
        .Take(pageSize);