Attempting to create an MVC project using EF and the Model first approach.
In order to implement it in a way that the Web and data portions are loosely coupled I'm attempting to implement the repository pattern, but, after reading many articles I'm still trying to grasp what objects my Repository interface should return or how they should bind/map to the 'M' model in my MVC project.
Here's a very simplistic example of what I'm asking.
//Repository Interface
public interface IMemberRepository
{
Member GetById(int id);
IEnumerable<Member> FindByName(string name);
}
//Repository Interface Implementation
public class MemberRepository : IMemberRepository
{
//My DB Context object created by EF
private MyContainer context;
public MemberRepository(MyContainer context)
{
this.context = context;
}
public Member GetById(int id)
{
return context.Members.SingleOrDefault(x => x.Id == id);
}
public IEnumerable<Member> FindByName(string name)
{
return context.Members.Find(x => x.name == name);
}
}
So using Ninject as my DI framework I could call this from my controller as follows:
public class GroupsController : Controller
{
public ViewResult Find(string name)
{
IMemberRepository repo =
ObjectFactory.Instance.CreateInstance<IMemberRepository>();
return repo.FindByName(name);
}
}
At this point I'm just not understanding how my Member object (from the EF model) is supposed to bind/map to my 'MVC' member model object. It seems I must be missing some sort of mapping layer or I'm just completely off track. If I were to reference my EF generated class directly it feels like I'm negating the point of using an interface and DI framework. Any advice or direction at this point would be appreciated.
Your IMemberRepository interface and its implementation MemberRepository look right to me. That is how I structure my database code as well.
Moving to the MVC world, I would create view models which you populate from your data model. This will give you the flexibility of adding any attributes or additional properties that you need in your view.
This would be the workflow:
Fetch object(s) from repository
Populate view model objects with all the data from your repository object(s)
Return the view model to your view from the controller
Related
I am creating an application with ASP.NET MVC and Entity framework code first. I am using repository and unit of work pattern with influence of from following link.
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Here I have question about the implementation of Unit Of Work in that link unit of work is implemented via directly writing entities in class itself like.
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
}
Do you think that implementation is good enough because every time I add/remove entities I need to change my Unit of work class. I believe that Unit of work should not be dependent on entities. Because in my application based on Client feedback we are going to frequently add/remove entities.
I may sound stupid but let me know your views on that.
The Unit of Work pattern is already implemented in Entity Framework.
The DbContext is your Unit of Work.
Each IDbSet is a Repository.
using (var context = new SchoolContext()) // instantiate our Unit of Work
{
var department = context.Departments.Find(id);
}
There are a few flavors of the UnitOfWorkPattern. The one you are describing is a show everything, there is a hide everything approach as well. In the hide approach the unit of work references the DbContext.SaveChanges() method and nothing else; sounds like what you want.
public YourContext : DbContext, IContext{}
public interface IUnitOfWork{
void Commit();
}
public UnitOfWork : IUnitOfWork{
private readonly IContext _context;
//IOC should always inject the same instance of this, register it accordingly
public UnitOfWork(IContext context){
_context = context;
}
void Commit(){
// try catch the validation exception if you want to return the validations this
// way if your confident you've already validated you can put a void here or
// return the intfrom save changes make sure you handle the disposing properly,
// not going into that here you also may be doing other stuff here, have multiple
// "contexts" to save in a single transaction or we have contextProcessors that
// do stuff based on items in the context
_context.SaveChanges();
}
}
This leaves the issue of how you get your repositories into the classes that need them if you are not taking them from the UnitOfWork. This is best handled by an IOC framework. Again here there are a couple options. Once is to register the UnitOfWork as a single instance per request and have it injected into your custom Repository class.
public interface IRepository<T>
{
IQueryable<T> Records();
//other methods go here
}
public Repository : IRepository<T>
{
private IContext _context;
// same instance of context injected into the unit of work, this why when you Commit
// everything will save, this can get tricky if you start adding Add, Update and stuff
// but EF does have the support needed.
public Repository(IContext context)
{
_context = context;
}
public Records()
{
return _context.Set<T>();
}
}
public class SomeService : ISomeService{
private readonly _myObjectRepository;
public SomeService(IRepository<MyObject> myObjectRepository){
_myObjectRepository = myObjectRepository;
}
}
Personally I consider the IDbSet an sufficient abstraction so I no longer create repositories. In
order to inject the IDbSets from the context though you need to register them as instances that you
extract from the context in your IOC setup. This can be complex and depending on your skills you
could find yourself in the situation where you have to register each IDbSet which I know you are trying to avoid.
What's nice about using the IDbSet is you have access to simple methods like Add and can avoid some of the more complex parts of working with Entity and DbEntity in a generic sense.
public class SomeService : ISomeService {
private readonly _myObjectSet;
// requires specialized IOC configurations because you have to pull this instance from
// the instance of the context, personally don't know how to do this with a single
// registration so this has the same problem as having to add each new repository to the
// unit of work. In this case each new Entity I add to the context requires I add an IOC
// registration for the type.
public SomeService(IDbSet<MyObject> myObjectSet){
_myObjectSet= myObjectSet;
}
}
Try passing the SchoolContext to the GenericRepository:
public GenericRepository<T>
{
private SchoolContext _context;
public GenericRepository(SchoolContext context)
{
_context = context;
}
public Get(int id)
{
return _context.Set<T>().Find(id);
}
}
And use:
using(var context = new SchoolContext())
{
var departmentRepository = new GenericRepository<Department>(context);
var department = departmentRepository.Get(1);
}
I want to create a repository class to separate out my data logic from my controllers. I am using a ViewModel to represent some data that will be filled with data from different tables.
Here are some questions I have:
For a method like GetAll(), do I return an IQueryable<MyViewModel> or IQueryable<Entity>? If I return viewmodels, how do I cope with a GetAll() that pulls thousands of records?
Do I create a constructor for my custom ViewModel class that takes the Entity as a parameter to do the mapping? (I'm still unfamiliar with automapper so just need an understanding on how to do this from a design point of view)
Again, my main concern is a method like GetAll() which would pull many records. If I did a foreach loop to translate each Entity into a ViewModel seems like a lot of overhead. My thought was to put a reference inside the custom ViewModel class to the IQueryable<Entity> to access from the collection, and have the ListViewModel just have indexers or something like that which reference the collection property.
1) For a method like GetAll(), do I return an IQueryable or IQueryable? If I return viewmodels, how do I cope with a GetAll() that pulls thousands of records?
IQueryable<Entity>. The repository doesn't deal with view models. Think of the repository as something that is defined in a separate class library that doesn't reference your ASP.NET MVC application which is where your view models live. It is the ASP.NET MVC application that references this library.
2) Do I create a constructor for my custom ViewModel class that takes the Entity as a parameter to do the mapping? (I'm still unfamiliar with automapper so just need an understanding on how to do this from a design point of view)
No. Don't create constructors in your view models especially if you want your controller actions to take those view models as action parameters (think of a POST action). The reason for this is that the default model binder will no longer know how to instantiate your view model and you will have to write custom model binders.
So AutoMapper or manually map.
Example with manual mapping which is what you could start with:
public ActionResult SomeAction()
{
IEnumerable<Entity> entities = Repository.GetAll();
IEnumerable<MyViewModel> model = entities.Select(x => new MyViewModel
{
Prop1 = x.Prop1,
Prop2 = x.Prop2,
...
});
return View(model);
}
And once you get sick of writing this code move to AutoMapper:
public ActionResult SomeAction()
{
IEnumerable<Entity> entities = Repository.GetAll();
IEnumerable<MyViewModel> model = Mapper.Map<IEnumerable<Entity>, IEnumerable<MyViewModel>>(entities);
return View(model);
}
or if you write a custom action filter that uses the OnActionExecuted event to pull the domain model that was passed to the view, map it to the view model using AutoMapper and substitute the model with the view model for the view, you could further simplify the repetitive code:
[AutoMap(typeof(IEnumerable<Entity>), typeof(IEnumerable<MyViewModel>))]
public ActionResult SomeAction()
{
IEnumerable<Entity> entities = Repository.GetAll();
return View(entities);
}
Again, my main concern is a method like GetAll() which would pull many
records. If I did a foreach loop to translate each Entity into a
ViewModel seems like a lot of overhead.
Don't be concerned about that. Pulling your records will be a magnitude slower than looping and mapping to the view model.
There are many different ways to do this, but to start simply, I would return an IEnumerable<T> for your GetAll() method. However, you'll probably want to implement paging in some fashion. You might want to setup a generic repository that does your basic data access for most scenarios and returns an Enumerable. You could reserve a single method that should be reserved for more complicated queries and returns an IQueryable<T>. The basic stripped down implementation might look like below.
public class Repository<T> : IRepository<T> where T : class
{
internal ObjectContext _objectContext;
internal ObjectSet<T> _objectSet;
public Repository(ObjectContext objectContext)
{
_objectContext = objectContext;
_objectSet = objectContext.CreateObjectSet<T>();
}
public IQueryable<T> GetQuery()
{
return _objectSet;
}
public IEnumerable<T> GetAll()
{
return GetQuery().ToList();
}
public IEnumerable<T> Find(Func<T, bool> where)
{
return _objectSet.Where<T>(where);
}
public T Single(Func<T, bool> where)
{
return _objectSet.SingleOrDefault<T>(where);
}
public List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending)
{
return ascending
? GetQuery().Where(where).OrderBy(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList()
: GetQuery().Where(where).OrderByDescending(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList();
}
public void Delete(T entity)
{
_objectSet.DeleteObject(entity);
}
public void Add(T entity)
{
_objectSet.AddObject(entity);
}
}
And the Interface would look like
public interface IRepository<T> where T : class
{
IQueryable<T> GetQuery();
IEnumerable<T> GetAll();
IEnumerable<T> Find(Func<T, bool> where);
T Single(Func<T, bool> where);
List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending);
void Delete(T entity);
void Add(T entity);
}
The above can function as the beginning of a simple generic repository. Once you have your entities, you don't need AutoMapper, it just makes life easier as many ViewModels have the same properties as your entities. You can simply define a new ViewModel or List of ViewModels and map the properties on your own.
List<ViewModel> vm = new List<ViewModel>();
foreach (var e in entities)
{
ViewModel v = new ViewModel();
v.something = e.something;
// perform the rest
vm.Add(v);
}
*That was quite a bit to type, sorry about any typos :)
I think you may have a misunderstanding of the view model and it's purpose. You don't need to create a view model for every entity in your database, as it seems you want to do; you just create a view model for each view you want to render. Hence the term "view model"--it organizes the data in the form of a model that your view can be strongly typed to.
You wouldn't, for example, want to create a separate view model for every entity returned by a GetAll(). In a simple scenario of displaying a gridview of all records you would probably just need a single viewmodel with one property:
public class MyViewModel
{
public List<MyRecord> AllRecords {get;set;}
}
You would populate this view model in the controller
public ActionResult SomeAction()
{
var viewmodel = new MyViewModel{AllRecords = GetAll()};
return View(viewModel);
}
Have a look at this blog post by Rachael Appel for a really concise discussion.
I have this really basic code in a MVC controller action. It maps an Operation model class to a very basic OperationVM view-model class .
public class OperationVM: Operation
{
public CategoryVM CategoryVM { get; set; }
}
I need to load the complete list of categories in order to create a CategoryVM instance.
Here's how I (try to) create a List<OperationVM> to show in the view.
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(
dest => dest.CategoryVM,
opt => opt.MapFrom(
src => CreateCatVM(src.Category, context.Categories)
// trouble here ----------------^^^^^^^
)
);
var opVMs = ops.Select(op => Mapper.Map<Operation, OperationVM>(op))
.ToList();
return View(opVMs);
}
}
All works great first time I hit the page. The problem is, the mapper object is static. So when calling Mapper.CreateMap(), the instance of the current DbContext is saved in the closure given to CreateMap().
The 2nd time I hit the page, the static map is already in place, still using the reference to the initial, now disposed, DbContext.
The exact error is:
The operation cannot be completed because the DbContext has been disposed.
The question is: How can I make AutoMapper always use the current context instead of the initial one?
Is there a way to use an "instance" of automapper instead of the static Mapper class?
If this is possible, is it recommended to re-create the mapping every time? I'm worried about reflection slow-downs.
I read a bit about custom resolvers, but I get a similar problem - How do I get the custom resolver to use the current context?
It is possible, but the setup is a bit complicated. I use this in my projects with help of Ninject for dependency injection.
AutoMapper has concept of TypeConverters. Converters provide a way to implement complex operations required to convert certain types in a separate class. If converting Category to CategoryVM requires a database lookup you can implement that logic in custom TypeConverter class similar to this:
using System;
using AutoMapper;
public class CategoryToCategoryVMConverter :
TypeConverter<Category, CategoryVM>
{
public CategoryToCategoryVMConverter(DbContext context)
{
this.Context = context;
}
private DbContext Context { get; set; }
protected override CategoryVM ConvertCore(Category source)
{
// use this.Context to lookup whatever you need
return CreateCatVM(source, this.Context.Categories);
}
}
You then to configure AutoMapper to use your converter:
Mapper.CreateMap<Category, CategoryVM>().ConvertUsing<CategoryToCategoryVMConverter>();
Here comes the tricky part. AutoMapper will need to create a new instance of our converter every time you map values, and it will need to provide DbContext instance for constructor. In my projects I use Ninject for dependency injection, and it is configured to use the same instance of DbContext while processing a request. This way the same instance of DbContext is injected both in your controller and in your AutoMapper converter. The trivial Ninject configuration would look like this:
Bind<DbContext>().To<SomeContext>().InRequestScope();
You can of course use some sort of factory pattern to get instance of DbContext instead of injecting it in constructors.
Let me know if you have any questions.
I've found a workaround that's not completely hacky.
Basically, I tell AutoMapper to ignore the tricky field and I update it myself.
The updated controller looks like this:
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(dest => dest.CategoryVM, opt => opt.Ignore());
var opVMs = ops.Select(
op => {
var opVM = Mapper.Map<Operation, OperationVM>(op);
opVM.CategoryVM = CreateCatVM(op.Category, context.Categories);
return opVM;
})
.ToList();
return View(opVMs);
}
}
Still curious how this could be done from within AutoMapper...
The answer from #LeffeBrune is perfect. However, I want to have the same behavior, but I don't want to map every property myself. Basically I just wanted to override the "ConstructUsing".
Here is what I came up with.
public static class AutoMapperExtension
{
public static void ConstructUsingService<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExression, Type typeConverterType)
{
mappingExression.ConstructUsing((ResolutionContext ctx) =>
{
var constructor = (IConstructorWithService<TSource, TDestination>)ctx.Options.ServiceCtor.Invoke(typeConverterType);
return constructor.Construct((TSource)ctx.SourceValue);
});
}
}
public class CategoryToCategoryVMConstructor : IConstructorWithService<Category, CategoryVM>
{
private DbContext dbContext;
public DTOSiteToHBTISiteConverter(DbContext dbContext)
{
this.dbContext = dbContext;
}
public CategoryVM Construct(Category category)
{
// Some commands here
if (category.Id > 0)
{
var vmCategory = dbContext.Categories.FirstOrDefault(m => m.Id == category.Id);
if (vmCategory == null)
{
throw new NotAllowedException();
}
return vmCategory;
}
return new CategoryVM();
}
}
// Initialization
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(type => nInjectKernelForInstance.Get(type));
cfg.CreateMap<Category, CategoryVM>().ConstructUsingService(typeof(CategoryToCategoryVMConstructor));
};
We're using EF Code first, and have a data context for our sales database. Additionally, we have a class that sits on top of our data context and does some basic CRUD operations.
For example, we have the following function:
public static T Create<T>(int userId, T entity) where T : class, IAllowCreate
{
if (entity == null)
throw new ArgumentNullException("entity");
using (SalesContext dc = new SalesContext())
{
dc.Set<T>().Add(entity);
dc.SaveChanges();
return entity;
}
}
I found an example of how to create fake contexts and IDBset properties. I started implementing that, but I ran in to an issue.
We use dc.Set() quite liberally (as seen above) in our code, as we attempt to create generic CRUD methods. Instead of having a ReadCustomer, ReadContact etc, we would just do Read(). However, dc.Set returns a DbSet, not an IDbSet, so I'm not able to mock that.
Has anyone been able to mock or fake DbContext and still use the Set functionality?
interface ISalesContext
{
IDbSet<T> GetIDbSet<T>();
}
class SalesContext : DbContext, ISalesContext
{
public IDbSet<T> GetIDbSet<T>()
{
return Set<T>();
}
}
I used a different name, but you can use the new operator if you prefer to hide the regular implementation.
I have an application using ASP.NET MVC, Unity, and Linq to SQL.
The unity container registers the type AcmeDataContext which inherits from System.Data.Linq.DataContext, with a LifetimeManager using HttpContext.
There is a controller factory which gets the controller instances using the unity container. I set-up all my dependencies on the constructors, like this:
// Initialize a new instance of the EmployeeController class
public EmployeeController(IEmployeeService service)
// Initializes a new instance of the EmployeeService class
public EmployeeService(IEmployeeRepository repository) : IEmployeeService
// Initialize a new instance of the EmployeeRepository class
public EmployeeRepository(AcmeDataContext dataContext) : IEmployeeRepository
Whenever a constructor is needed, the unity container resolves a connection, which is used to resolve a data context, then a repository, then a service, and finally the controller.
The issue is that IEmployeeRepository exposes the SubmitChanges method, since the service classes DO NOT have a DataContext reference.
I have been told that the unit of work should be managed from outside the repositories, so it would seem I ought to remove SubmitChanges from my repositories. Why is that?
If this is true, does this mean that I have to declare an IUnitOfWork interface and make every service class dependent upon it? How else can I allow my service classes to manage the unit of work?
You shouldn't try to supply the AcmeDataContext itself to the EmployeeRepository. I would even turn the whole thing around:
Define a factory that allows creating a new unit of work for the Acme domain:
Create an abstract AcmeUnitOfWork that abstracts away LINQ to SQL.
Create a concrete factory that can allows creating new LINQ to SQL unit of works.
Register that concrete factory in your DI configuration.
Implement an InMemoryAcmeUnitOfWork for unit testing.
Optionally implement convenient extension methods for common operations on your IQueryable<T> repositories.
UPDATE: I wrote a blog post on this subject: Faking your LINQ provider.
Below is a step-by-step with examples:
WARNING: This will be a loooong post.
Step 1: Defining the factory:
public interface IAcmeUnitOfWorkFactory
{
AcmeUnitOfWork CreateNew();
}
Creating a factory is important, because the DataContext implement IDisposable so you want to have ownership over the instance. While some frameworks allow you to dispose objects when not needed anymore, factories make this very explicit.
Step 2: Creating an abstract unit of work for the Acme domain:
public abstract class AcmeUnitOfWork : IDisposable
{
public IQueryable<Employee> Employees
{
[DebuggerStepThrough]
get { return this.GetRepository<Employee>(); }
}
public IQueryable<Order> Orders
{
[DebuggerStepThrough]
get { return this.GetRepository<Order>(); }
}
public abstract void Insert(object entity);
public abstract void Delete(object entity);
public abstract void SubmitChanges();
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected abstract IQueryable<T> GetRepository<T>()
where T : class;
protected virtual void Dispose(bool disposing) { }
}
There are some interesting things to note about this abstract class. The Unit of Work controls and creates the Repositories. A repository is basically something that implements IQueryable<T>. The repository implements properties that return a specific repository. This prevents users from calling uow.GetRepository<Employee>() and this creates a model that is very close to what you are already doing with LINQ to SQL or Entity Framework.
The unit of work implements Insert and Delete operations. In LINQ to SQL these operations are placed on the Table<T> classes, but when you try to implement it this way it will prevent you from abstracting LINQ to SQL away.
Step 3. Create a concrete factory:
public class LinqToSqlAcmeUnitOfWorkFactory : IAcmeUnitOfWorkFactory
{
private static readonly MappingSource Mapping =
new AttributeMappingSource();
public string AcmeConnectionString { get; set; }
public AcmeUnitOfWork CreateNew()
{
var context = new DataContext(this.AcmeConnectionString, Mapping);
return new LinqToSqlAcmeUnitOfWork(context);
}
}
The factory created a LinqToSqlAcmeUnitOfWork based on the AcmeUnitOfWork base class:
internal sealed class LinqToSqlAcmeUnitOfWork : AcmeUnitOfWork
{
private readonly DataContext db;
public LinqToSqlAcmeUnitOfWork(DataContext db) { this.db = db; }
public override void Insert(object entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.db.GetTable(entity.GetType()).InsertOnSubmit(entity);
}
public override void Delete(object entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.db.GetTable(entity.GetType()).DeleteOnSubmit(entity);
}
public override void SubmitChanges();
{
this.db.SubmitChanges();
}
protected override IQueryable<TEntity> GetRepository<TEntity>()
where TEntity : class
{
return this.db.GetTable<TEntity>();
}
protected override void Dispose(bool disposing) { this.db.Dispose(); }
}
Step 4: Register that concrete factory in your DI configuration.
You know self best how to register the IAcmeUnitOfWorkFactory interface to return an instance of the LinqToSqlAcmeUnitOfWorkFactory, but it would look something like this:
container.RegisterSingle<IAcmeUnitOfWorkFactory>(
new LinqToSqlAcmeUnitOfWorkFactory()
{
AcmeConnectionString =
AppSettings.ConnectionStrings["ACME"].ConnectionString
});
Now you can change the dependencies on the EmployeeService to use the IAcmeUnitOfWorkFactory:
public class EmployeeService : IEmployeeService
{
public EmployeeService(IAcmeUnitOfWorkFactory contextFactory) { ... }
public Employee[] GetAll()
{
using (var context = this.contextFactory.CreateNew())
{
// This just works like a real L2S DataObject.
return context.Employees.ToArray();
}
}
}
Note that you could even remove the IEmployeeService interface and let the controller use the EmployeeService directly. You don't need this interface for unit testing, because you can replace the unit of work during testing preventing the EmployeeService from accessing the database. This will probably also save you a lot of DI configuration, because most DI frameworks know how to instantiate a concrete class.
Step 5: Implement an InMemoryAcmeUnitOfWork for unit testing.
All these abstractions are there for a reason. Unit testing. Now let's create a AcmeUnitOfWork for unit testing purposes:
public class InMemoryAcmeUnitOfWork: AcmeUnitOfWork, IAcmeUnitOfWorkFactory
{
private readonly List<object> committed = new List<object>();
private readonly List<object> uncommittedInserts = new List<object>();
private readonly List<object> uncommittedDeletes = new List<object>();
// This is a dirty trick. This UoW is also it's own factory.
// This makes writing unit tests easier.
AcmeUnitOfWork IAcmeUnitOfWorkFactory.CreateNew() { return this; }
// Get a list with all committed objects of the requested type.
public IEnumerable<TEntity> Committed<TEntity>() where TEntity : class
{
return this.committed.OfType<TEntity>();
}
protected override IQueryable<TEntity> GetRepository<TEntity>()
{
// Only return committed objects. Same behavior as L2S and EF.
return this.committed.OfType<TEntity>().AsQueryable();
}
// Directly add an object to the 'database'. Useful during test setup.
public void AddCommitted(object entity)
{
this.committed.Add(entity);
}
public override void Insert(object entity)
{
this.uncommittedInserts.Add(entity);
}
public override void Delete(object entity)
{
if (!this.committed.Contains(entity))
Assert.Fail("Entity does not exist.");
this.uncommittedDeletes.Add(entity);
}
public override void SubmitChanges()
{
this.committed.AddRange(this.uncommittedInserts);
this.uncommittedInserts.Clear();
this.committed.RemoveAll(
e => this.uncommittedDeletes.Contains(e));
this.uncommittedDeletes.Clear();
}
protected override void Dispose(bool disposing)
{
}
}
You can use this class in your unit tests. For instance:
[TestMethod]
public void ControllerTest1()
{
// Arrange
var context = new InMemoryAcmeUnitOfWork();
var controller = new CreateValidController(context);
context.AddCommitted(new Employee()
{
Id = 6,
Name = ".NET Junkie"
});
// Act
controller.DoSomething();
// Assert
Assert.IsTrue(ExpectSomething);
}
private static EmployeeController CreateValidController(
IAcmeUnitOfWorkFactory factory)
{
return new EmployeeController(return new EmployeeService(factory));
}
Step 6: Optionally implement convenient extension methods:
Repositories are expected to have convenient methods such as GetById or GetByLastName. Of course IQueryable<T> is a generic interface and does not contains such methods. We could clutter our code with calls like context.Employees.Single(e => e.Id == employeeId), but that's really ugly. The perfect solution to this problem is: extension methods:
// Place this class in the same namespace as your LINQ to SQL entities.
public static class AcmeRepositoryExtensions
{
public static Employee GetById(this IQueryable<Employee> repository,int id)
{
return Single(repository.Where(entity => entity.Id == id), id);
}
public static Order GetById(this IQueryable<Order> repository, int id)
{
return Single(repository.Where(entity => entity.Id == id), id);
}
// This method allows reporting more descriptive error messages.
[DebuggerStepThrough]
private static TEntity Single<TEntity, TKey>(IQueryable<TEntity> query,
TKey key) where TEntity : class
{
try
{
return query.Single();
}
catch (Exception ex)
{
throw new InvalidOperationException("There was an error " +
"getting a single element of type " + typeof(TEntity)
.FullName + " with key '" + key + "'. " + ex.Message, ex);
}
}
}
With these extension methods in place, it allows you to call those GetById and other methods from your code:
var employee = context.Employees.GetById(employeeId);
What the nicest thing is about this code (I use it in production) is that -once in place- it saves you from writing a lot of code for unit testing. You will find yourself adding methods to the AcmeRepositoryExtensions class and properties to the AcmeUnitOfWork class when new entities are added to the system, but you don't need to create new repository classes for production or testing.
This model has of course some shortcomes. The most important perhaps is that LINQ to SQL isn't abstract away completely, because you still use the LINQ to SQL generated entities. Those entity contain EntitySet<T> properties which are specific to LINQ to SQL. I haven't found them to be in the way of proper unit testing, so for me it's not a problem. If you want you can always use POCO objects with LINQ to SQL.
Another shortcome is that complicated LINQ queries can succeed in test but fail in production, because of limitations (or bugs) in the query provider (especially the EF 3.5 query provider sucks). When you do not use this model, you are probably writing custom repository classes that are completely replaced by unit test versions and you will still have the problem of not being able to test queries to your database in unit tests. For this you will need integration tests, wrapped by a transaction.
A last shortcome of this design is the use of Insert and Delete methods on the Unit of Work. While moving them to the repository would force you to have a design with an specific class IRepository<T> : IQueryable<T> interface, it prevents you from other errors. In the solution I use myself I also have InsertAll(IEnumerable) and DeleteAll(IEnumerable) methods. It is however easy to mistype this and write something like context.Delete(context.Messages) (note the use of Delete instead of DeleteAll). This would compile fine, because Delete accepts an object. A design with delete operations on the repository would prevent such statement from compiling, because the repositories are typed.
UPDATE: I wrote a blog post on this subject that describes this solution in even more detail: Faking your LINQ provider.
I hope this helps.
If combining unit of work and repository patterns, some people advocate that UoW should be managed outside of repository so that you could create two repositories (say, CustomerRepository and OrderRepository) and pass them the same UoW instance ensuring that all the changes to the DB will be done atomically when you finally call UoW.Complete().
In a mature DDD solution however, there should not be need for both UoW and a repository. This is because is such a solution aggregate boundaries are defined is such a way, that there is no need of atomic changes involving more than one repository.
Does this answer your question?