Hello,
I inherited a project that uses MVC, linq to sql and the repository pattern (technically i think it's a mix of a repo pattern with a service pattern in one). The site intermittently gets an error that says there is already an open datareader associated with a command which must be closed. Doing some reading, it appears that making use of using statements would fix this as the context would be disposed each time it is called upon.
However, in this repo pattern, the context and constructor is created dynamically with the following class:
public class Repository<T> where T : DataContext { protected T db; public Repository(string connectionString) { var myConstructor = CreateConstructor(typeof(T), typeof(string)); db = (T)myConstructor(connectionString); } public delegate object ConstructorDelegate(params object[] args); public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters) { var constructorInfo = type.GetConstructor(parameters); var paramExpr = Expression.Parameter(typeof(Object[])); var constructorParameters = parameters.Select((paramType, index) => Expression.Convert( Expression.ArrayAccess( paramExpr, Expression.Constant(index)), paramType)).ToArray(); var body = Expression.New(constructorInfo, constructorParameters); var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr); return constructor.Compile(); } }
This is used like so:
public class ItemRepository : Repository<SomeDBContextClass>, IItemRepository { // the db object in the Repository class is used here in any following repository methods public IItem GetItem(int itemID) { var item = db.Item.FirstOrDefault(s => s.ID == itemID) ?? new Item(); return item; } }
Now, since the repo is getting a data context from this inherited class, there is no way to implement a using statement right? In other solutions people were saying that a simple .tolist will be enough to get rid of these errors but I've tried this and it doesn't seem to help, plus when there's a large amount of items there could be a performance hit from what stackoverflow comments are suggesting.
I started to comment out the inherit and adding a using new db context in each method, but we use AutoMapper and it errors saying that I can't map a disposed object. Is this common or is this an automapper quirk? I guess I could assign the item locally and then map it, so it doesn't really matter but it was just something else to pile onto my confusion.
Should I rip all this out and instantiate the context in each repo method? I get that the above code reduces the work of setting up a constructor and readonly member in each repo class but I feel like it's abstracting too far and is being more of a burden than useful. Even still, the db context is being injected... how do you using that? do I have to call dispose() in the end of every repo method?
I'm considering just dropping it all together and rebuilding the back end with EF but I don't really have the time allotted to do this.
I'm reading a lot about "unit of work" but that's something new to me as well and like I said I don't really have a lot of time allotted to me to fix this issue, I'm worried I'm going to fix it incorrectly and make it worse down the road.
I guess the main question is for the repository pattern, how do you properly dispose a connection if the repo is getting it's context injected? Does DI automatically dispose and call new every time it is needed? If it does then why am I getting these datacontext connection open issues? That doesn't add up to me. Surely the repo pattern handles this somehow but we just aren't implementing it properly?
Trying to better understand dbcontext using/reusing and the repository pattern