Dependency Injection with Entity Framework
August 21, 2013
Problem: how do you use Entity Framework, in database-first mode, when following the dependency injection development patterns?
Answer: take advantage of partial classes and manually create the interface. The following notes are just a sketch without full details.
For this demonstration, I'll create a new Entity Framework "ADO.NET Data Model" with a couple of tables and two stored procedure calls. This is a quick-and-dirty demonstration, so I'm not trying to setup Entity Framework and my procedure calls in an ideal fashion; it will be "just enough" for the demo.
Now open the auto-generated class file for the model. Right click and choose Refactor > Extract Interface. Select the operations that you want to include in the interface. Typically, I like to expose the entire table collection and the methods.
This action just updated the auto-generated file; you will lose that change next time you update the model
from the database. Here's where the partial class comes in. Copy the class declaration line (public
partial class IbaUnitTestEntities: ObjectContext, ClassLibrary1.IIbaUnitTestEntities
. Create a new
file with the same name as the model class, and paste that line in. Remove the implementation of ObjectContext.
Result:
partial class IbaUnitTestEntities: IIbaUnitTestEntities { }
Now back to the interface file. Change it to be public. We need one more method call in there, one that
is in ObjectContext and therefore was omitted by Visual Studio in the refactor command: the SaveChanges command.
And, we need the interface to implement IDisposable so that we can wrap the object in a using
statement (or try/catch/finally).
public interface IIbaUnitTestEntities : IDisposable { int SaveChanges(); ObjectSet<Location> Locations { get; } ObjectSet<Person> People { get; } ObjectResult<Person> Person_Get(Guid? id, string openId, bool? all); ObjectResult<Person> Person_Get(Guid? id, string openId, bool? all, System.Data.Objects.MergeOption mergeOption); int Person_Save(Guid? id, string firstName, string lastName, string openId, string emailAddress, string phoneNumber, string address1, string address2, string city, string state, string zipCode, string country, bool? hasBeenTrained, bool? hasClipboard, short? personStatus, short? personRole); }
Compile your code - it should be succesful, with no further edits. Now let's look at using an Abstract Factory class for dependency injection.
public interface IFactory { IIbaUnitTestEntities CreateDatabaseConnection(); } public class Factory : IFactory { public IIbaUnitTestEntities CreateDatabaseConnection() { return new IbaUnitTestEntities(); } }
Now the main program needs to instantitate the factory and inject it into a dependent class. For this demonstration, I'm taking the simple approach rather than using a DI container like Ninject, Spring, or Unity.
public class Program { public static void Main(string[] args) { var factory = new Factory(); var demo = new Class1(factory); demo.DemonstrateSomeCalls(); } }
Finally, let's see the some code that uses the Entity Framework without having an explicit dependence on the code generated by EF. Take particular note that this code snippet shows the interface and not the concrete class generated by EF.
public class Class1 { private readonly IFactory factory; public Class1(IFactory inputFactory) { if (inputFactory == null) { throw new ArgumentNullException("inputFactory"); } factory = inputFactory; } public void DemonstrateSomeCalls() { using (IIbaUnitTestEntities db = factory.CreateDatabaseConnection()) { // Call a stored procedure var allPeople = db.Person_Get(null, "", true) .ToList(); // Update the address for the first person in the list. // Bad code! Doesn't check for null var firstPerson = allPeople.FirstOrDefault(); firstPerson.Address1 = "new address"; db.SaveChanges(); // Add a person db.People.AddObject(new Person() { FirstName = "Stephen" }); db.SaveChanges(); } } }
No TrackBacks
TrackBack URL: http://www.safnet.com/fcgi-bin/mt/mt-tb.cgi/113
Leave a comment