1

I have an isolated problem with cached data in a web app, and understand that it's cached due to the way the datacontext is reused. My Repository classes return IQueryable types, so I'm unable to refresh the datacontext by closing & reopening it. For example, my CustomerRepository has this datacontext constructor:

private CAClassesDataContext context = new CAClassesDataContext();

And all database interaction methods then use this context, e.g:

public IQueryable<Customer> Customers
{
     get { return context.Customers; }
}

If I try to use the context in a using block:

using(CAClassesDataContext context = new CAClassesDataContext())
{
...
}

I can't access the related classes as lazy loading is used. I've tried adding:

context.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer)

after the update but the problem still exists. How can I force LINQ to SQL to use the database data instead of the cached?

UPDATE: Thanks to answers provided by Steve & Andrew I was able to resolve the issue. My respositories now have a constructor like this:

[Inject]
public CustomerRepository (CAClassesDataContext Context)
{
    context = Context;
}

And in my Ninject bindings added:

Bind<CAClassesDataContext>().ToSelf().InRequestScope();

My project uses a custom membership provider an I was unable to use the above technique due to the provider's parameterless constructor. To get round this I added methods to the respository which get called before & after the databse lookup:

repository.CreateContext();
var cust = repository.GetAllCustomers().SingleOrDefault(c => c.Username == username);
repository.DisposeContext();
markpsmith
  • 4,860
  • 2
  • 33
  • 62

2 Answers2

1

The data context should only exist during a "unit of work". It sounds like you are mis-using your DC and keeping it (or the repository class) hanging around for longer than it should.

Try instantiating the repository each time your BLL needs to perform a series of database operations, and dispose of it when finished. Or this isn't practical (e.g. if you are using IoC to inject the repository instance into your BLL) then perhaps add a method to the repository to allow the BLL to spin up a DC prior to starting a unit of work, and another method to dispose of it afterwards.

Andrew Stephens
  • 9,413
  • 6
  • 76
  • 152
  • I am injecting my repositories into a base class which all the BLL classes then derive from. Regarding your last suggestion, if I create CreateContext() and DisposeContext() methods in each repository, could I call these from the base class Initialize() and Finalize() methods? – markpsmith Feb 22 '12 at 10:42
0

As @Andrew Stephens says, your context object should be being created and used on a per-request basis.

Instead of hard-coding it to be created inside a repository, inject it into the repository via its constructor. If you're using an IoC container you may have the ability to have the context managed on a per-request basis for you (Ninject provides this, for example), otherwise you can wrap your context in a request-scoped data store object using HttpContext.Items, as detailed in this article.

Steve Wilkes
  • 7,085
  • 3
  • 29
  • 32
  • I'm interested in what you say about managing the context on a per-request basis, the UnitOfWork is a new one on me! I am using Ninject - do you have a good example of how I could implement this? I read your reply here: (http://stackoverflow.com/questions/9115376/where-should-i-create-the-unit-of-work-instance-in-an-asp-net-mvc-3-application) but it just boggled my mind. – markpsmith Feb 22 '12 at 10:54
  • Typed without checking it, but I believe you can register your context with Ninject like `Bind().ToSelf().InRequestScope()`to have Ninject manage it on a per-request basis. If you hit a brick wall with that let me know and I'll go through the way of doing it yourself. Incidentally you should really have your context injected via an interface, but one thing at a time, I guess :) – Steve Wilkes Feb 22 '12 at 13:09