0

In an effort to make my entities persistent ignorant and make my repositories testable, I've implemented a repository pattern like so:

public interface IJobRepository : IRepository<Job>
{
    Job GetJobById(int jobId); //Special case where I'm eager loading other entities
    void SaveJob(Job job, Job originalJob);
}

public class JobRepository : IJobRepository
{
    private readonly IContext _context;

    public JobRepository()
    {
        _context = new CustomObjectContext();
    }

    public JobRepository(UnitOfWork unitOfWork)
    {
        _context = unitOfWork.Context;
    }

    //Basic GetAll, GetById, Add and Delete methods from IRepository<T> Interface here
    //omitted for brevity

    public Job GetJobById(int jobId)
    {
        var job = _context.Jobs.Include("Company").Include("Location").
            Include("PlantInfo").Where(j => j.Jobid == jobId).SingleOrDefault();

        _context.DisposeContext();

        return job;
    }

    public void SaveJob(Job job, Job originalJob)
    {
        if (job.Jobid > 0)
        {
            // Update
            _context.Jobs.Attach(originalJob);
            _context.PlantInfoes.Attach(originalJob.PlantInfo);
            _context.Jobs.ApplyCurrentValues(job);
            _context.PlantInfoes.ApplyCurrentValues(job.PlantInfo);

        Note: ApplyCurrentValues is an extension method I'm using on the ObjectSet

        }
        else
        {
            // Create
            _context.Jobs.AddObject(job);
        }

        _context.Save();
    }
}

public class UnitOfWork
{
    private readonly IContext _context;

    public UnitOfWork()
    {
        _context = new CustomObjectContext();
    }

    public UnitOfWork(IContext context)
    {
        _context = context;
    }

    public string Save()
    {
        return _context.Save();
    }

    internal IContext Context
    {
        get { return _context; }
    }
}

public interface IContext
{
    IObjectSet<Job> Jobs { get; }
    IObjectSet<Company> Companies { get; }
    IObjectSet<Location> Locations { get; }
    IObjectSet<PlantInfo> PlantInfoes { get; }
    string Save();
}

My ObjectContext inherits from IContext...So my understanding is that I will only use the overloaded constructor on the repository to facilitate unit tests or to use it in the case that I want to use the same context (not desirable based on this post I found on SO "Entity Framework and Connection Pooling" -- Is this right?

Also, assuming the context only gets disposed when the repository is garbage collected, I have to dispose the context explicitly to avoid the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker." exception when attaching the entity prior to a save.

That said, what is the best practice for managing the DataContext in a manner that keeps your entities persistent ignorant and repositories testable?

Note: This is an asp.net webapplication; UnitOfWork and IContext implementation was based on examples from "Programming Entity Framework", Second Edition by Julia Lerman Ch24.

Thanks in advance!

Community
  • 1
  • 1
Rich
  • 1,810
  • 3
  • 25
  • 35

1 Answers1

0

Firstly, I would ensure that whatever my "consumable" object is (either repository or unit of work, depending on your setup) implements IDisposable. When your consumbed object is disposed of, then you would dispose your underlying context.

For instance, if you're using your UnitOfWork as the consumable object (the one that gets created and called in your application), it would look something like:

public class UnitOfWork : IDisposable
{
    // All the other stuff you had before plus:
    public void Dispose ()
    {
        if (_context != null)
        {
            _context.Dispose ();
        }
    }
}

(Note: This can also be done on your repositories if they're the ones being consumed directly)

And then, you have a few options in your application. If you are going to use the UnitOfWork directly, you can use it like:

public void SomeMethodThatAccessesYourData ()
{
    using (var unitOfWork = new UnitOfWork (/*Load in the context*/))
    {
        // Access your data here.
    }
}

Or, in your Web Forms or MVC object you can use constructor injection and dispose of it when the Web Forms or MVC object is disposed of:

//  If you're using MVC:
public class MyController : Controller
{
    private UnitOfWork _unitOfWork;

    public MyController (UnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public override Dispose (bool Disposing)
    {
        if (Disposing && _unitOfWork != null)
        {
            _unitOfWork.Dispose ();
        }
    }
}

The same idea stands for a web forms Page.

The main reason for using the constructor overload is for Inversion of Control (IOC). It helps with both unit testing and with production code when used with an IoC Container. WebForms doesn't lend itself well to IoC, but it is really easy with MVC.

Edit

I don't really see the connection with your repositories and the unit of work. Usually you access the repositories from a unit of work or, in other implementations, you request a unit of work from your target repository. In your implementation (which I understand is not your own) there seems to be no need for both.

Edit 2

If the UoW is overkill for your application, and you know you can use IoC to inject your IContext, and you don't have very many repositories, you can do something like:

public IRepository<T> : IDisposable { }
public IJobRepository : IRepository<Job> { /* All the stuff you put here */ }
public JobRepository : IJobRepository
{
    private IContext _context;

    ...

    public void Dispose ()
    {
        if (_context != null)
        {
            _context.Dispose ();
        }
    }

    public JobRepository (IContext context)
    {
         _context = context;
    }
}

Then, how you use it depends on your specific task. I'm not a fan of this direct use of IRepository, but this answer is getting too long.

Jim D'Angelo
  • 3,914
  • 3
  • 22
  • 38
  • Someone suggested using IDisposable but I didn't fully understand how to implement it -- I get it now, thanks @James. In regards to the Edit; I'm not seeing the connection either which was confusing me so I just left it there to make the repo testable. I was using this constructor previously but wasn't sure about it: `public Job(){ var unitOfWork = new UnitOfWork(); _context = unitOfWork.Context; }` this should force the repo to use the unit of work right? If so, would it be best to put implement IDisposable in the uow or repo? – Rich Dec 31 '11 at 16:34
  • BTY - Im using a UI Pattern Framework based on MVP. So I'm using IoC w constructor injection to call methods from my repos in the presenter and want to avoid calling the uow directly from my presenter. – Rich Dec 31 '11 at 16:40
  • This is a somewhat complex subject for an answer. There are a lot off good blogs that discuss how to do something like this. If you have more questions, feel free to email me at james at thegeekco dot com or hit me up on Twitter (found on my profile). – Jim D'Angelo Dec 31 '11 at 17:07
  • I agree. Thanks for offering the extra help. I think your answer was as concise as could be. I'll do some more research on this sub and hit you up on email. Thanks! – Rich Dec 31 '11 at 17:33