Below is the series outline; again, this is Part 3.
- Part 1: Setup
- This post involves downloading and creating the SQL Server database, setting up the Visual Studio solution and project structure, and generating the out-of-the-box Entity Framework (EF/EF4) data model from the newly created database.
- Part 2: Creating the Repositories and Unit of Work (UoW)
- This is the meat of the series. This post includes downloading some T4 templates, settings a few parameters, and generating the Repositories and Unit of Work (UoW) using the T4 templates and EF4 data model.
- Part 3: Review Some of The Generated Code
- This post will review a few of the generated class/interfaces that the T4 code generation created.
- Part 4: Using EF, Repository & UoW in an ASP.NET MVC 3 Project
- This post includes wiring up the EF4 data model, repositories, and UoW to StructureMap dependency injection container and use of these products in an ASP.NET MVC 3 Web application project.
- IReadOnlyRepository.cs
- The IReadOnlyRepository is the base interface that all the entity specific interfaces inherit from. The IReadOnlyRepository contains (you guessed it…) read-only interfaces to the persistence layer.
- IRepository.cs
- The IRepository interface extends the IReadOnlyIRepository interface to include creating and deleting or entities.
- The original intent of separating the IReadOnlyRepository and IRepository interfaces was that so POCO object backed by data views (VIEWs on a database) would not inherit creating and deleting functionality.
- The IRepository interface extends the IReadOnlyIRepository interface to include creating and deleting or entities.
- IUnitOfWork.cs
- The IUnitOfWork interface handles all the transactions and changes needed to persist modifications to the persistence mechanism.
IReadOnlyRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace Chinook.Core.Repository { /// <summary> /// Generic Read-Only Repository Contract /// </summary> /// <typeparam name="T"></typeparam> public interface IReadOnlyRepository<t> where T : class { /// <summary> /// Gets an IQueryable sequence of entities of type T. /// </summary> /// <returns></returns> IQueryable<t> Queryable(); /// <summary> /// Gets an IEnumerable sequence of all entites of type T. /// </summary> /// <returns></returns> IEnumerable<t> All(); /// <summary> /// Get an IEnumerable sequence of entities of type T filtered on the @where predicate. /// </summary> /// <param name="where">The where predicate.</param> /// <returns></returns> IEnumerable<t> Find(Expression<func><t bool ,>> where); /// <summary> /// Gets a single entity in a sequence of entities of type T using the filtered @where predicate. /// </summary> /// <param name="where">The where predicate.</param> /// <returns></returns> T Single(Expression<func><t bool ,>> where); /// <summary> /// Gets the first entity in a sequence of entities of type T using the filtered @where predicate. /// </summary> /// <param name="where">The where predicate.</param> /// <returns></returns> T First(Expression<func><t bool ,>> where); /// <summary> /// Gets a single entity (or default of entity of type T) in a sequence of entities of type T using the filtered @where predicate. /// </summary> /// <param name="where">The where predicate.</param> /// <returns></returns> T SingleOrDefault(Expression<func><t bool ,>> where); /// <summary> /// Gets a first entity (or default entity of type T) in a sequence of entities of type T using the filtered @where predicate. /// </summary> /// <param name="where">The where predicate.</param> /// <returns></returns> T FirstOrDefault(Expression<func><t bool ,>> where); } }
IRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Chinook.Core.Repository { /// <summary> /// Generic Repository Contract. /// </summary> /// <typeparam name="T"></typeparam> public interface IRepository<t> : IReadOnlyRepository<t> where T : class { /// <summary> /// Adds the specified entity to the respository of type T. /// </summary> /// <param name="entity">The entity to add.</param> void Add(T entity); /// <summary> /// Deletes the specified entity to the respository of type T. /// </summary> /// <param name="entity">The entity to delete.</param> void Delete(T entity); /// <summary> /// Attaches the specified entity to the respository of type T. /// </summary> /// <param name="entity">The entity to attach.</param> void Attach(T entity); } }
namespace Chinook.Core.Repository { /// <summary> /// Unit of Work Contract /// </summary> public interface IUnitOfWork { /// <summary> /// Commits the changes to the data store. /// </summary> void Commit(); } }
- IObjectContext
- this is an interface that defines the contract used by the ObjectContextAdapter, the EFUnitOfWork, and ultimately the ObjectContext.
- ObjectContextAdapter
- this is a simple adapter class that wraps the Entity Framework’s ObjectContext object for use in the Repository/Unit of Work paradigm. This class implements the IObjectContext contract.
- RepositoryIQueryableExtensions
- this class includes a single method: Include. Include is an IQueryable(of T) extension method that affords the ‘Eager Loading’ functionality provided by the Entity Framework. But, since our solution abstracts the Entity Framework, the EF ‘Eager Loading’ Include method is not available. This extension method gives our solution the functionality back. You may not realize this yet, but that is a really cool ‘feature!’
- The implementation of this Include extension method was taken from the following article on MSDN: http://msdn.microsoft.com/en-us/ff714955.aspx – this is a great article and one that I got quite a few ideas for this series and solution.
- this class includes a single method: Include. Include is an IQueryable(of T) extension method that affords the ‘Eager Loading’ functionality provided by the Entity Framework. But, since our solution abstracts the Entity Framework, the EF ‘Eager Loading’ Include method is not available. This extension method gives our solution the functionality back. You may not realize this yet, but that is a really cool ‘feature!’
Template Force Code (Re)Generation – or NOT
Of this six T4 templates included in the download, all but the Domain.Poco.tt contain the following settings:// answers the question: Force generation of file even if the code file exists? bool forceCodeGeneration = false;
StructureMap configuration for Repositories and Services
If you’re reading this blog series, I’m sure you’re familiar with Dependency Injection (DI). There are quite a few DI containers for .NET; however, my favorite is StructureMap. Why is it my favorite? Well, when I first endeavored on the DI/IOC concept, StructureMap is what those around me recommended. I was not disappointed! The documentation could be better – it’s a little out-of-date; however, the DI API for StructureMap is extremely easy to use and relatively easy to understand. You will first need to overcome the DI/IOC paradigm challenges, but once the 'light goes on,’ you’ll wonder how you survived without it… Okay, back to the Bonuses… Expand the Repository.Implementation.EF.tt and Service.Implementation.tt T4 templates. Below are screenshots of the two T4 template generated outputs. Notice the highlighted files… All four of these files contain StructureMap Dependency Injection registration code. The files stating with __StructureMap.* contain ‘raw’ registration code that you can use however you’d like. The other two files (EFRepositoryRegistry.cs.txt and ServicesRegistry.cs.txt) contain StructureMap Registry derived classes. According to the StructureMap documentation, Registries are the recommended way to configure StructureMap:“The Registry DSL is the recommended way to configure StructureMap, and creating Registry classes is the recommended way of using the Registry DSL.”
We will be using the code in these files in the next post in this series… Stay tuned…
In summary, we reviewed a few of the code files that the T4 templates generated, discussed how to NOT to overwrite your manual code changes to the generated files, and discovered how the T4 templates generate StuctureMap DI registration snippets and Registries for you.
In the next post in this series, we will put all the fruits of our labor (okay, the code generated labor) to use in an ASP.NET MVC 3 Web Application.
Thanks for reading…
2 comments:
Great article,Thanks a lot..
@Onur - thanks for the kind words...
Post a Comment