Wednesday, August 21, 2013

Generate Repository Pattern for Entity Framework DbContext

Generating Repositories for the database entities could be a big repetitive task with similar code. The project at https://efrepository.codeplex.com solves the problem by generating a T4 Template for the edmx model. The T4 Template then generates the required repositories, the Unit of Work pattern, and also provides a factory for the repositories.

The template, however, generates code for the ObjectContext approach.

I have modified the template, so that it can be used with the EntityFramework 5.0 and above to generate the relevant repositories.

Here is the Template below.


//==========================================================================
<#@ template language="C#" debug="true" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
 
<#@ output extension=".cs"#>
<#
 
// This needs to be set to the .edmx file that you want to process.
string edmxFile = FindEDMXFileName(); // @"Model1.edmx";
 
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
MetadataTools ef = new MetadataTools(this);
 
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace <#= code.VsNamespaceSuggestion() #>
{ 
 public interface IRepository 
 {
  IUnitOfWork UnitOfWork { get; set; }
  IQueryable All();
  IQueryable Where(Func expression);
  void Add(T entity);
  void Delete(T entity);
 }
}<#
 
 
EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(edmxFile);
EntityContainer container = ItemCollection.GetItems().FirstOrDefault();
EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
 
foreach (EntityType entity in ItemCollection.GetItems().OrderBy(e => e.Name))
{;
 
 if(!DoesFileExist(entity.Name + "Repository.cs"))
 {
  fileManager.StartNewFile(entity.Name + "Repository.cs");
  #>using System;
using System.Linq;
using System.Collections.Generic;
 
namespace <#= code.VsNamespaceSuggestion() #>
{   
 <#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#>Repository : EFRepository<<#=code.Escape(entity)#>>, I<#=code.Escape(entity)#>Repository
 {
 
 }
 
 <#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#> interface I<#=code.Escape(entity)#>Repository
 {
 
 }
}<#
 }
 else
 {
  fileManager.StartNewFile(entity.Name + "Repository.cs");
  this.Write(OutputFile(entity.Name + "Repository.cs"));
 }
}
 
fileManager.StartNewFile("IUnitOfWork.cs");
#>using System.Data.Objects;
using System.Data.Entity;
 
namespace <#= code.VsNamespaceSuggestion() #>
{
 public interface IUnitOfWork
 {
  DbContext Context { get; set; }
  void Commit();
  bool LazyLoadingEnabled { get; set; }
  bool ProxyCreationEnabled { get; set; }
  string ConnectionString { get; set; }
 }
}<# fileManager.StartNewFile("RepositoryIQueryableExtensions.cs");
#>using System.Data.Objects;
using System.Linq;
 
namespace <#= code.VsNamespaceSuggestion() #>
{
 public static class RepositoryIQueryableExtensions
 {
  public static IQueryable Include
   (this IQueryable source, string path)
  {
   var objectQuery = source as ObjectQuery;
   if (objectQuery != null)
   {
    return objectQuery.Include(path);
   }
   return source;
  }
 }
}<# fileManager.StartNewFile("EFRepository.cs");
#>using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
 
namespace <#= code.VsNamespaceSuggestion() #>
{
 public class EFRepository : IRepository where T : class
 {
  public IUnitOfWork UnitOfWork { get; set; }
  
  private DbSet _dbSet;
 
  private DbSet DbSet
  {
   get
   {
    if (_dbSet == null)
    {
     _dbSet = UnitOfWork.Context.Set();
    }
    return _dbSet;
   }
  }
 
  public virtual IQueryable All()
  {
   return DbSet.AsQueryable();
  }
 
  public IQueryable Where(Func expression)
  {
   return DbSet.Where(expression).AsQueryable();
  }
 
  public void Add(T entity)
  {
   DbSet.Add(entity);
  }
 
  public void Delete(T entity)
  {
   DbSet.Remove(entity);
  }
 
 }
}<#fileManager.StartNewFile("EFUnitOfWork.cs");
#>using System.Data.Objects;
using System.Data.Entity;
 
namespace <#= code.VsNamespaceSuggestion() #>
{
 public class EFUnitOfWork : IUnitOfWork
 {
  public DbContext Context { get; set; }
 
  public EFUnitOfWork()
  {
   Context = new <#=code.Escape(container)#>();
  }
 
  public void Commit()
  {
   Context.SaveChanges();
  }
  
  public bool LazyLoadingEnabled
  {
   get { return true; }
   set { }
  }
 
  public bool ProxyCreationEnabled
  {
   get { return true; }
   set { }
  }
  
  public string ConnectionString
  {
   get { return Context.Database.Connection.ConnectionString; }
   set { Context.Database.Connection.ConnectionString = value; }
  }
 }
}
<#fileManager.StartNewFile("RepositoryHelper.cs");
#>
namespace <#= code.VsNamespaceSuggestion() #>
{
 public static class RepositoryHelper
 {
  public static IUnitOfWork GetUnitOfWork()
  {
   return new EFUnitOfWork();
  }  
  <# foreach (EntityType entity in ItemCollection.GetItems().OrderBy(e => e.Name))
{; #>
 
  public static <#=code.Escape(entity)#>Repository Get<#=code.Escape(entity)#>Repository()
  {
   return new <#=code.Escape(entity)#>Repository();
  }
 
  public static <#=code.Escape(entity)#>Repository Get<#=code.Escape(entity)#>Repository(IUnitOfWork unitOfWork)
  {
   var repository = new <#=code.Escape(entity)#>Repository();
   repository.UnitOfWork = unitOfWork;
   return repository;
  }  
<# } #>
 }
}<# fileManager.Process();
#>
 
 
<#+
 
bool DoesFileExist(string filename)
{   
 return File.Exists(Path.Combine(GetCurrentDirectory(),filename)); 
}
 
string OutputFile(string filename)
{
 using(StreamReader sr = new StreamReader(Path.Combine(GetCurrentDirectory(),filename)))
 {
  string contents = sr.ReadToEnd();
  return contents;
 }
}
 
string GetCurrentDirectory()
{
 string executingDirectoryName = "";
 string stackTraceFileName = new StackTrace(true).GetFrame(0).GetFileName();
 if (String.IsNullOrEmpty(stackTraceFileName))
 {
  throw new ArgumentException("No value was specified for the 'directoryName' configuration parameter" +
   ", and we could not figure out the file name from the stack trace (most likely because of running " +
   "the template with debug='False' specified in the <\u0023@ template \u0023> directive.");
 }
 else
 {  
  executingDirectoryName = Path.GetDirectoryName(stackTraceFileName);
 } 
 return executingDirectoryName;
}
 
string FindEDMXFileName()
{
 string edmxFile = "";
    
 string[] entityFrameworkFiles = Directory.GetFiles(GetCurrentDirectory(), "*.edmx");
 if(entityFrameworkFiles.Length > 0)
  edmxFile = entityFrameworkFiles[0];
 
 return edmxFile;
}
#>

No comments:

Post a Comment