Tuesday, March 15, 2011

Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 2: Creating the Repositories and Unit of Work (UoW)

This is Part 2 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the Entity Framework 4 and the Repository and Unit of Work Patterns.

Below is the series outline; again, this is Part 2.
Now on to Part 2… The following download contains some T4 templates that I’ve created and/or modified from other sources.  These T4 templates will build all the code necessary to create our Domain Models, Domain Model Metadata (e.g. Data Annotations), Repositories, Services, and Unit of Work all by pointing each related T4 to the EF data model (edmx) created in Part 1 of this series. T4 Templates Download. Go ahead and download the zip file and un-compress the contents into a directory directly under the solution root.  The solution’s root directory should look something like the following, where the T4_EF4_Repository directory is the directory that contains the uncompressed files from the download. p2Solutionlist00 Open up the T4_EF4_Repository directory.  The directory should contain a ‘Source’ directory and a single PowerShell file: image The ‘Source’ directory should contain six T4 template files (*.tt) image What are these files?  Well, the files with the *.tt extension are the T4 templates that will generate the code, while the single file with the *.ps1 extension is a PowerShell script.  The following briefly describes each file:
  • Domain.Poco.tt
    • This template generates the POCO (Domain) classes from your EF data model.
  • Domain.Poco.Metadata.tt
    • This template generates data annotations/metadata ‘buddy’ classes for the POCOs.
  • Repository.Interface.tt
    • This template generates all the associated Repository Interfaces/Contracts, including:
      • base IReadOnlyRepository and  IRepository Interfaces
      • IUnitOfWork Interface
      • I<POCO_ClassName>Repository Interface for each POCO class generated from you EF data model.
  • Repository.Implementation.EF.tt
    • This template generates the EF-related concrete class implementations defined by the IRepository Interfaces/Contracts.
  • Services.Interface.tt
    • This template generates a light-weight Service Interfaces/Contracts for each POCO class.
  • Services.Implementation.tt
    • This template generates the concrete class implementation defined by the Service Interfaces/Contracts.
  • prepareT4Templates.ps1
    • This is just a simple PowerShell script that contains project-specific settings to assist in generation T4 templates specific to the project – in our scenario, the Chinook application solution.
Open up the Chinook Visual Studio Solution. We should now have a Visual Studio Solution with thee Projects (Chinook.Core, Chinook.Data.EF, Chinook.Infrastructure) and a directory located at the solution root containing the T4 templates and single PowerShell file. Open up T4_EF4_Repository directory in Windows Explorer.  Right-click the PowerShell file and select ‘Edit’ from the context menu.  image This will open up the PowerShell editor and display the content of the PowerShell file.  As you can see, this is simple script that does a find/replace, creates a new directory, and creates new T4 templates that contain the replaced settings.
#*****************************************************************
#*****************************************************************
#*********** BEGIN Template Parameters ***************************
#*****************************************************************

# path to the project's edmx data model (entity framework data model)
$edmxFilePath = "..\..\Chinook.Data.Ef\Chinook.edmx"
# the namepace name where the solution's domain models live 
$domainModelNamespace = "Chinook.Core.Domain"
# the namespace name where the solution's services will live
$serviceInterfaceNamespace = "Chinook.Core.Services"
# the namespace name where the solution's repository will live
$repositoryInterfaceNamespace = "Chinook.Core.Repository"

#*****************************************************************
#*********** END Template Parameters *****************************
#*****************************************************************

function createDirectory($directory){
New-Item $directory -type directory -force    
}

function removeDestinationFile($file){
if(Test-Path $file){ Remove-Item $file }
}

function writeout($file){
$sourceFile = "Source/" + $file
$destinationDirectory = "Solution/"    
$destinationFile = $destinationDirectory + $file

createDirectory($destinationDirectory)    
removeDestinationFile($destinationFile)

(Get-Content $sourceFile) |
Foreach-Object {$_ -replace "\[\*\*EDMX_FILE_PATH\*\*\]", $edmxFilePath} | 
Foreach-Object {$_ -replace "\[\*\*DOMAIN_MODEL_NAMESPACE\*\*\]", $domainModelNamespace} |
Foreach-Object {$_ -replace "\[\*\*SERVICE_INTERFACE_NAMESPACE\*\*]", $serviceInterfaceNamespace} |
Foreach-Object {$_ -replace "\[\*\*REPOSITORY_INTERFACE_NAMESPACE\*\*\]", $repositoryInterfaceNamespace} |
Set-Content $destinationFile
}

$files = @("Domain.Poco.tt", "Domain.Poco.Metadata.tt", "Repository.Interface.tt", "Service.Interface.tt", "Repository.Implementation.EF.tt", "Service.Implementation.tt")

foreach($file in $files){
writeout($file)
}
As I mentioned above, the PowerShell file will generate T4 templates specific to your project.  If you followed along in Part 1, these setting variables are taken from the namespaces that we specified in the last step.  If you missed it, the following table duplicates our previous efforts:
Directory Namespace
Domain Chinook.Core.Domain
Repository Chinook.Core.Repository
Services Chinook.Core.Services
The following are the project-specific settings:
  • $edmxFilePath
    • relative path to the solution’s EF data model (edmx)

  • $domainModelNamespace
    • the namespace where the solution’s POCO’s live – see namespace table above
  • $serviceInterfaceNamespace
    • the namespace where the solution’s Service Interfaces/Contracts live – see namespace table above
  • $repositoryInterfaceNamespace
    • the namespace where the solution’s Repository Interfaces/Contracts live – see namespace table above
If you followed through this post's series, there is no need to change the aforementioned settings.  They are already set to the proper solution-specific settings.  If not, go ahead and change the necessary settings. You can run the PowerShell file within the editor of by right-clicking the PowerShell file and click ‘Run with PowerShell.’  However, since we already have the file open in the editor, we are going to use the editor. Click the ‘Run’ button on the editor’s toolbar: image If when running the PowerShell file you receive the following error, you do not have the proper permission to execute PowerShell scripts:
File C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 cannot be loaded. The file C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 is not digitally signed. The script will not execute on the system. Please see "get-help about_signing" for more details..
You have a couple choices to get around this, but the easiest is to set the PowerShell execution policy to ‘unrestricted’ using the following PowerShell command (* you must be running PowerShell as an Administrator).  Go ahead and run this command in the PowerShell console in the bottom pane of the PowerShell editor:
Set-ExecutionPolicy UnRestricted
Accept the ‘Execution Policy Change’ dialog message – the dialog only appears if you are using the editor.  If you are using the non-editor PowerShell console, this ‘Execution Policy Change’ message will only echo to the console. Sorry about that little hiccup.  If you’re not comfortable with setting the execution policy to 'unrestricted,’ you get reverse the policy back to ‘restricted’ once you’re done generating the necessary T4 templates by using the following PowerShell command:
Set-ExecutionPolicy Restricted
For more PowerShell documentation, check out MSDN. Close the PowerShell editor. Okay, back to the tutorial…  Once you execute the PowerShell script, the T4_EF4_Repository directory will now contain a new ‘Solution’ sub-directory and will contain six T4 templates with the project-specific settings defined earlier.  These are the templates that we will be using in our application. image image Still with me?  I hope so.  I know – it’s a bit long the first time, but it’s really pretty simple and will be worth the effort.  Hang in there… Next, if you haven’t already done so, open up the Chinook Visual Studio Solution.  We are now going to add the POCO generator to the EF Data Model.  If you don’t have the ADO.NET POCO Entity Generator template installed, you will need to add it via the Visual Studio Extension Manager from the Visual Studio Gallery.

Adding the POCO Template

  • Open up the Chinook.edmx file so the EF data model is visible in the designer (this is located in the Chinook.Data.EF project)
  • Right-click on an empty area of the EF data model canvas and select ‘Add Code Generation Item…’
p2addcodegen
  • This will bring up the ‘Add new Item Dialog,’ in which you will choose the ADO.NET POCO Entity Generator template (via the Installed Templates –> Code node)
p2addpoco
  • Set the ‘Name’ of the ADO.NET POCO Entity Generator item to ‘Poco.tt’
  • Save the EF data model (edmx file) and build the Chinook.Data.EF project.
  • Delete the Poco.tt file from the Chinook.Data.EF project
    • ** DO NOT delete the Poco.Context.tt file. 

Add the T4 Templates to the Solution

We are now going to add the T4 templates that we generated earlier.
Project Directory T4 Template (Solution directory)
Chinook.Core Domain Domain.Poco.tt
Chinook.Core Domain Domain.Poco.Metadata.tt
Chinook.Core Repository Repository.Interface.tt
Chinook.Core Services Service.Interface.tt
Chinook.Data.EF * add using Project node * Repository.Implementation.EF.tt
Chinook.Infrastructure Services Service.Implementation.tt
For each one of the following directories in the list above, add the associated T4 template in listed order by right-clicking the respective directory, clicking ‘Add / Existing Item…’, navigating to the T4_EF4_Repository/Solution directory (in the root of the solution) and selecting the associated T4 template.  A couple of notes…
  • You may need to use the ‘All File(*.*)’ filter on the ‘Add Existing Item’ dialog.
  • Ensure that you select the proper T4 templates  (e.g. use the ‘Solution’ directory and NOT the ‘Source’ directory)
image image

Build the Solution and Resolve Dependencies

Now, go ahead and build the solution and resolve any dependencies that appear in the Error List.  You will get errors on the ‘ObjectContext’ derived class (ChinookEntities in our scenario).  To resolve these errors, you will need to add a reference to the Domain namespace where the POCOs classes live (we identified this earlier in the ‘namespace’ table).  In our scenario, just add the following using statement to the ‘ChinookEntities’ class…
using Chinook.Core.Domain;
Build the solution again.  All the dependencies should now be resolved and the solution should build with no errors. In summary, we walked through the process of implementing a solution that separates concerns into specific behaviors using the Entity Framework 4 and the Repository and Unit of Work Patterns using T4 templates to generate the code using our EF data model

In the next post in this series, we will review a few of the generated class/interfaces that the T4 code generation templates created.

Thanks for reading…

2 comments:

aaronnewton said...

I had some difficulty getting the paths to work (I'm using a slighly different setup to the one suggested). Eventually I ended up modifying the templates using the following approach - http://stackoverflow.com/questions/3548026/get-referenced-projects-path-in-t4-template/14304115#14304115

aaronnewton said...
This comment has been removed by the author.