Modifying Entity Framework for use by a Repository and Unit of Work Pattern

The major refactoring occurs near the top of the file, before defining the various DbSet entities.  The following was refactored:

  • addition of a static constructor, where we can, among other things, check for the existence of the database
  • Explicitly disabled lazy loading
  • Added a new method for use with IDbSet
  • Added new method to override SaveChanges()

Note:  We will also be adding two additional classes to the project.

The result will resemble something similar to the following:


 

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ATMS.DAL
{
 using System;
 using System.Data.Entity;
 using System.Data.Entity.Infrastructure;
 using System.Data.Objects;
 using System.Data.Objects.DataClasses;
 using System.Linq;

 public partial class AtmsEntities : DbContext, IDbContext
 {

 static AtmsEntities()
 {
 // if required, at this point we can check for a db's existance,
 // create a new database (code first), or seed the db with values
 Database.SetInitializer<AtmsEntities>(null);
 }


 public AtmsEntities()
 : base("name=AtmsEntities")
 {

 // To disable lazy loading, add the following to your Entity Container definition:
 // <EntityContainer Name="MyEntitiesContext" annotation:LazyLoadingEnabled="false">
 // This will automaticall add the following line when generating
 // this.Configuration.LazyLoadingEnabled = false;

 // Remove the following line if lazy loading has been disabled through the EntityContainer definition:
 Configuration.LazyLoadingEnabled = false;

 }


 // Refactored for use by a generic repository
 public new IDbSet<T> Set<T>() where T : class
 {
 return base.Set<T>();
 }

 public override int SaveChanges()
 {
 // this.ApplyStateChanges();
 return base.SaveChanges();
 }

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
 throw new UnintentionalCodeFirstException();
 }

 public DbSet<ABBREVIATION> ABBREVIATIONS { get; set; }

 

Disable Lazy Loading

Disabling lazy loading is recommended, as it prevents inflated data sets from being created.

You can disable lay loading by adding the following to your Entity Container:


 
<EntityContainer Name="MyEntitiesContext" annotation:LazyLoadingEnabled="false">

 

 

The generated *.cs file already has lazy loading explicitly but I have left in some notes in case you choose to use the Entity Container method.

Here is the relevant output section.  Reference the *.tt section to see how this was generated:


 

public AtmsEntities()
 : base("name=AtmsEntities")
 {

 // To disable lazy loading, add the following to your Entity Container definition:
 // <EntityContainer Name="MyEntitiesContext" annotation:LazyLoadingEnabled="false">
 // This will automaticall add the following line when generating
 // this.Configuration.LazyLoadingEnabled = false;

 // Remove the following line if lazy loading has been disabled through the EntityContainer definition:
 Configuration.LazyLoadingEnabled = false;

 }

 

Additional Classes

Before this is up and running you will also need to add two more classes to your Entity Framework Project:

  • IDbContext.cs
  • DbContextExtensions.cs

These two should be accessible to your Model.Context.cs:

IDbContext.cs:


 

public interface IDbContext
{
 IDbSet<T> Set<T>() where T : class;
 int SaveChanges();
 DbEntityEntry Entry(object o);
 void Dispose();
}

 

DbContextExtensions.cs:


 

public static class DbContextExtension
{
 public static void ApplyStateChanges(this DbContext dbContext)
 {
 //if (dbContext.ChangeTracker.Entries().Select(dbEntityEntry =>
 // dbEntityEntry.Entity as IObjectState).Any(entityState => entityState == null))

foreach (var dbEntityEntry in dbContext.ChangeTracker.Entries())
 {
 var entityState = dbEntityEntry.Entity as IObjectState;
 if (entityState == null)
 {
 throw new InvalidCastException(
 "All entities must implement the IObjectState interface." +
 "This interface must be implemented so each entity state " +
 "can be explicitly determined when updating graphs.");
 }
 }
 }

private static EntityState ConvertState(ObjectState state)
 {
 switch (state)
 {
 case ObjectState.Added:
 return EntityState.Added;
 case ObjectState.Modified:
 return EntityState.Modified;
 case ObjectState.Deleted:
 return EntityState.Deleted;
 default:
 return EntityState.Unchanged;
 }
 }
}

 

Conclusion

Repository and unit of work patterns are intended to create an abstraction layer between the data access layer and the business logic layer of an application, and easily allow you to swap out objects for unit testing.

We discussed how to modify an Entity Framework Database First project for use with these patterns.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s