1

I have a repository class which is querying the EF DbContext like this:

public IEnumerable<ProductFilterData> GetAllProducts()
{
   return this.DataContext.Products.Select(x => new ProductFilterData { Id = x.Id, Name = x.Name, ProductDetailLevelCode = x.ProductDetailLevel.Code, Description = x.Description, ParentProductIds = x.ParentProducts.Select(p => p.Id) });
}

Which works fine. However, when I refactor this code to this:

public IEnumerable<ProductFilterData> GetAllProducts()
{
    return this.MapToProductFilterData(this.DataContext.Products);
}

private IEnumerable<ProductFilterData> MapToProductFilterData(IEnumerable<Product> products)
{
    return products.Select(x => new ProductFilterData { Id = x.Id, Name = x.Name, ProductDetailLevelCode = x.ProductDetailLevel.Code, Description = x.Description, ParentProductIds = x.ParentProducts.Select(p => p.Id) });
}

I get an exception:

There is already an open DataReader associated with this Command which must be closed first.

Why does passing a reference to the DbSet to a method cause a change in the behavior of EF? Incidentally, if I change the parameter type of MapToProductFilterData to IQueryable then it works. Also, if I remove the relationship mappings it also works.

Charlie
  • 10,227
  • 10
  • 51
  • 92

1 Answers1

4

You must change it to IQueryable because if you pass it as IEnumerable you actually execute query SELECT * FROM Product. Your method starts iterating the result set but your projection calls x.ParentProducts.Select(p => p.Id) which results in lazy loading of ParentProducts navigation property. Lazy loading opens second active data reader which is possible only if you have it enabled in connection string.

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Thanks. To clarify your point, a different Select extension method is being executed (the one for IEnumerable<> rather than IQueryable<>), which results in the different behavior. – Charlie Dec 16 '11 at 23:00