C# Problem Overview
I'm currently writing a data access layer for an application. The access layer makes extensive use of linq classes to return data. Currently in order to reflect data back to the database I've added a private data context member and a public save method. The code looks something like this:
private DataContext myDb;
public static MyClass GetMyClassById(int id)
DataContext db = new DataContext();
MyClass result = (from item in db.MyClasss
where item.id == id
result.myDb = db;
public void Save()
That's a gross over simplification but it gives the general idea. Is there a better way to handle that sort of pattern? Should I be instantiating a new data context every time i want to visit the db?
Solution 1 - C#
It actually doesn't matter too much. I asked Matt Warren from the LINQ to SQL team about this a while ago, and here's the reply:
> There are a few reasons we implemented > IDisposable: > > If application logic needs to hold > onto an entity beyond when the > DataContext is expected to be used or > valid you can enforce that contract by > calling Dispose. Deferred loaders in > that entity will still be referencing > the DataContext and will try to use it > if any code attempts to navigate the > deferred properties. These attempts > will fail. Dispose also forces the > DataContext to dump its cache of > materialized entities so that a single > cached entity will not accidentally > keep alive all entities materialized > through that DataContext, which would > otherwise cause what appears to be a > memory leak. > > The logic that automatically closes > the DataContext connection can be > tricked into leaving the connection > open. The DataContext relies on the > application code enumerating all > results of a query since getting to > the end of a resultset triggers the > connection to close. If the > application uses IEnumerable's > MoveNext method instead of a foreach > statement in C# or VB, you can exit > the enumeration prematurely. If your > application experiences problems with > connections not closing and you > suspect the automatic closing behavior > is not working you can use the Dispose > pattern as a work around.
But basically you don't really need to dispose of them in most cases - and that's by design. I personally prefer to do so anyway, as it's easier to follow the rule of "dispose of everything which implements IDisposable" than to remember a load of exceptions to it - but you're unlikely to leak a resource if you do forget to dispose of it.
Solution 2 - C#
Treat your datacontext as a resource. And the rule of using resource says
> "acquire a resource as late as > possible, release it as soon as its > safe"
Solution 3 - C#
DataContext is pretty lightweight and is intended for unit of work application as you are using it. I don't think that I would keep the DataContext in my object, however. You might want to look at repository patterns if you aren't going to use the designer generated code to manage your business objects. The repository pattern will allow you to work with your objects detached from the data context, then reattach them before doing updates, etc.
Personally, I'm able to live with the DBML designer generated code for the most part, with partial class implementations for my business and validation logic. I also make the designer-generated data context abstract and inherit from it to allow me to intercept things like stored-procedure and table-valued function methods that are added directly to the data context and apply business logic there.
A pattern that I've been using in ASP.NET MVC is to inject a factory class that creates appropriate data contexts as needed for units of work. Using the factory allows me to mock out the data context reasonably easy by (1) using a wrapper around the existing data context class so that it's mockable (mock the wrapper since DataContext is not easily mockable) and (2) creating Fake/Mock contexts and factories to create them. Being able to create them at will from a factory makes it so that I don't have to keep one around for long periods of time.