Code Re-factoring for the sample project attached with the post Repository, Specification, Unit of Work, Persistence Ignorance POCO with Microsoft ADO.NET Entity Framework 4.0 Beta 2. Brief explanation of the changes are included.
Hi, while I was preparing my post on Tame Your Software Dependencies with Dependency Injection & Common Service Locator Library, I have further refactored the sample project codes for my post on Repository, Specification, Unit of Work, Persistence Ignorance POCO with Microsoft ADO.NET Entity Framework 4.0 Beta 2.
The changes that I have made center around the MyCompany.Data.Entity project under the FrameworkSource logical folder as indicated below. Figure 1.0 and Figure 1.1 show the solution view of MyCompany.Data.Entity before and after code refactoring. After the code refactoring, you will see an additional project solution; MyCompany.Data holds all the interfaces/abstraction for implementing the Repository, Unit of Work and Specification pattern. The MyCompany.Data is totally decoupled from any data infrastructure concern (data access technology agnostic).
The UnitOfWork has been made an abstract class in the MyCompany.Data project from the concrete class in the MyCompany.Data.Entity. It includes a few abstract methods and a template method; CommitCore that the concrete class must implement. You can notice that the EntityUnitOfWork implement UnitOfWork abstract class in the MyCompany.Data.Entity. The EntityUnitOfWork provides unit of work implementation for any application that make use of the Entity Framework as data access infrastructure. However, anyone intends to implement a totally different unit of work implementation can choose to implement the IUnitOfWork interface which exposes only the Commit interface method.
The Repository class remain as an abstract class in the MyCompany.Data project. However, its protected properties; ObjectContext and ObjectSet have been moved into the higher level assembly/project; MyCompany.Data.Entity to break the coupling to the Microsoft Entity Framework in the MyCompany.Data project/assembly. So, I can say that the MyCompany.Data project/assembly is data access technology agnostic. The Repository class that provides an in-memory like collection interface for accessing domain objects against the Entity Data Source (ObjectContext) is now named as EntityRepository in the MyCompany.Data.Entity assembly/project.
The rest of the changes you can easily spot in the MyCompany.Data.Entity project. The changes are pretty on the names of the types such as the AspNetObjectSourceLifetimeManager, ScopeObjectSourceLifetimeManager and StaticObjectSourceLifetimeManager. The changes in their name are not necessary but I think changing it to ObjectSource instead of using the ObjectContext will more reflect the concrete data source lifetime manager inherits from the abstract class ObjectSourceLifetimeManager even though the three concrete class are actually managing the ObjectContext in the Entity Framework. By looking at ScopeObjectSourceLifetimeManager, you will know that it inherits from the abstract class ObjectSourceLifetimeManager.
The last, you will see there is an additional EntityUnitOfWorkFactory in the MyCompany.Data.Entity project which implements the IUnitOfWorkFactory interface. The simple static factory, UnitOfWorkFactory inside the MyCompany.Data.Entity project previously has been removed. The rationale is not to fix a particular UnitOfWorkFactory implementation required by the UnitOfWorkScope in MyCompany.Data project. Anyone can implement the IUnitOfWorkFactory interface to provide his own implementation of Unit of Work factory used by the UnitOfWorkScope. Anyway, the default implementation of UnitOfWorkScope is provided as it is. It is the way I think it should work and it may not meet the all the needs and expectations of some applications. Anyone can implement his own version of the UnitOfWorkScope in his own project or assembly to replace this default implementation. As you can see, the UnitOfWorkScope is being used in the higher level component; MyCompany.Data.Entity and MyCompany.Business.AppName business layer project. You can replace it with your own implementation in your higher level framework or bussiness project.
Finally, the idea of creating a separate MyCompany.Data project is to have a better level of abstraction and separation of concern. You can see better level of abstraction with several interfaces and abstract classes such as IUnitOfWork, IUnitOfWorkFactory, IUnitOfWorkScope, UnitOfWork and etc because the concrete implementations can be varied by programming against the abstraction or contract. By programming against the abstraction or contract, changes in the implementation of the abstraction won't affect the higher level component that depends on it.
Decoupling the higher level component from its lower level dependencies by interacting with the dependencies via interfaces rather than their concrete classes give another advantage. It facilitates unit testing as we can simply substitute the interface with fakes or mocks for any of the dependencies. Another term is called dependency inversion because we can supply any implementation of the dependencies via the interfaces to the higher level components normally through the parameterized constructors of the higher level type.
I have included the new updated project source codes in the code download section below. This source code will be used as reference project for my next post on Tame Your Software Dependencies with Dependency Injection & Common Service Locator Library.
Code Download : Repository, Specification, Unit of Work, Persistence Ignorance POCO with Microsoft. ADO.NET Entity Framework 4.0 Beta 2 - Code Update . (This application sample requires Visual Studio 2010 Beta 2/RC that can open C# project. Right click on the above link and choose Save Target As. Rename the extension from .pdf to .zip once you have downloaded the file. Let me know if you have any problem running the code.)
See you in my next post.
Bye and stay tune...