Posts tagged ‘Entity Framework’

Visual Studio 2010 - Beta 2

Whilst preparing for my Entity Framework 4.0 and Unit Testing presentation at the recent New England Code Camp, I came across an issue with my code that I couldn’t entirely understand. Picture the scenario:

In Visual Studio 2008 utilizing EF 1.0:

  • Create a repository Assembly that contains the model and entity classes (i.e. no POCO) for a group of tables in my DB
  • Create a Manager class to expose public functions / methods to retrieve data from the DB via the EntityContext
    [store the Manager.cs file in a common area and create a Link to it from the project].
  • Create an extension method that will handle the usage of Lambda expressions inside the context of .Include() [Did I say I hate "magic strings"?]
    [store the ObjectQueryExtension.cs file in a common area and create a Link to it from the project]
  • Create a simple Console app to call the methods on the Manager class
    [store the Program.cs file in a common area and create a Link to it from the project].

Visual Studio 2008

In Visual Studio 2010 Beta 2 utilizing EF 4.0:

  • Create a repository Assembly that contains the model and entity classes (i.e. no POCO) for a group of tables in my DB
  • Create a Manager class to expose public functions / methods to retrieve data from the DB via the EntityContext
    [create a Link to the Manager.cs file from the project in a common area].
  • Create an extension method that will handle the usage of Lambda expressions inside the context of .Include()
    [create a Link to the ObjectQueryExtension.cs file in the common area from the project]
  • Create a simple Console app to call the methods on the Manager class
    [create a Link to the Program.cs file in the common area from the project].

Visual Studio 2010 - Beta 2

As you will see, the only difference between the two solutions is the actual EntityFramework context definition; one utilizes EF 1.0 and the other EF 4.0.

Compile and execute both and it works perfectly, same Program.cs code for both (making the Console Application); same Manager.cs and ObjectQueryExtension.cs code for both (making the RepositoryManager assembly).

Now the fun starts. I then worked my way back to using Dependency Injection and created the unit test methods based on the VS 2010 project described above. When the compiler attempts to compile the following section of code:


IQueryable<Person> query = context.PersonSet
                               .Include(p => p.PersonalDetail)
                               .Include("FavoriteBeers.Beer")
                               .Include(p => p.Customer.Include<Customer, CustomerType>(c => c.CustomerType))
                               .Include(p => p.Addresses);

The following compile error was the result of the attempted compilation against the preceding code:


Ef4.0AndEf1.0\PocoInEF4.0\EFWorkshop.Poco.RepositoryManager\Manager.cs(78,53): error CS1660: Cannot convert lambda expression to type 'string' because it is not a delegate type
Ef4.0AndEf1.0\PocoInEF4.0\EFWorkshop.Poco.RepositoryManager\Manager.cs(78,58): error CS0311: The type 'EFWorkshop.Poco.Base.Entities.Customer' cannot be used as type parameter 'TSource' in the generic type or method 'EFWorkshop.Ef.Repository.ObjectQueryExtension.Include<TSource,TPropType>(TSource, System.Linq.Expressions.Expression<System.Func<TSource,TPropType>>)'. There is no implicit reference conversion from 'EFWorkshop.Poco.Base.Entities.Customer' to 'System.Data.Objects.DataClasses.IEntityWithRelationships'.
Ef4.0AndEf1.0\Common\ObjectQueryExtension.cs(118,33): (Related location)
Ef4.0AndEf1.0\PocoInEF4.0\EFWorkshop.Poco.RepositoryManager\Manager.cs(78,60): error CS1061: 'System.Linq.IQueryable<EFWorkshop.Poco.Base.Entities.Person>' does not contain a definition for 'Customer' and no extension method 'Customer' accepting a first argument of type 'System.Linq.IQueryable<EFWorkshop.Poco.Base.Entities.Person>' could be found (are you missing a using directive or an assembly reference?)

However, the following “magic string” laden Includes compile and execute fine:


IQueryable<Person> query = _context.People
    .Include("FavoriteBeers.Beer")
    .Include("PersonalDetail")
    .Include("Customer.CustomerType")
    .Include("Addresses");

Therefore it would seem that the non POCO based classes permit us having the Lambda expression based includes as described earlier; however the moment that POCO is introduced that style of Include is no longer viable – or is it?

  • Share/Bookmark

Wow – June 24th was the last entry! First of all I need to apologize for my bad blogging; I have no other excuse except for the volume of work AT work. Sure I could have re-prioritized and it may have made a difference, but I don’t think my employer would have been very pleased.

So, New England Code Camp, Microsoft Offices, Waltham, MA – full information can be found at http://www.thedevcommunity.org/Events/PresentationList.aspx?id=13. Today I am giving two presentations:

Using Entity Framework’s New POCO Features: Part 2 (Unit Testing)

Level: Intermediate

Starts: Oct 17 2009 2:50 PM

Ends: Sep 17 2009 4:05 PM

Room: MPR A

Speaker: James Phillips

In many cases Unit Testing is considered a chore rather than another development task and often ends up being the last task in a development cycle. More often than not, the sheer work involved in preparing unit tests for existing code can lead to the production of Integration Tests rather than true Unit Tests. Where a unit of code that is under test relies on an external resource, such as a Database or Configuration file, the dependency can lead to testing of the underlying mechanism as well as the unit being tested. This was especially true with Entity Framework 1.0 shipped with .NET Framework 3.5 Service Pack 1. With the advent of .NET Framework 4.0, the Entity Framework has advanced in favor of better Unit Testing with the use of POCO and the ability to create interfaces based on IObjectSet. This presentation will cover the examples that can lead to true Unit Testing as opposed to Integration Testing and provide valuable feedback metrics such as code coverage and automated build time reporting of results.

SCRUM and TFS

Level: Introductory

Starts: Oct 17 2009 4:10 PM

Ends: Sep 17 2009 5:25 PM

Room: Rhode Island

Speaker: James Phillips

SCRUM has grown in popularity and acceptance by many companies over the world with numbers of registered SCRUM Masters reaching 51,955 (11 March 2009 – Jeff Sutherland). Although SCRUM does not stipulate what tools to use to produce the necessary artifacts, Microsoft Team Foundation System provides a number of features via TFS Explorer that facilitate capturing the artifacts of SCRUM and is a useful tool for any SCRUM Master, Team and Product Owner. This presentation will highlight the SCRUM framework and show you practical use of TFS and other tools that facilitate the ceremonies and artifacts of SCRUM.

The slides and code are available for download here:

SCRUM_And_TFS.zip

EF_POCO_And_UnitTesting_slides.zip”

EF_POCO_And_UnitTesting_code.zip

EF_POCO_And_UnitTesting.zip

  • Share/Bookmark

After publishing the blog article on Mocking in EF 2.0, Diego Vega (Microsoft Program Manager Entity Framework and LINQ to SQL Product Teams in Redmond) pointed out that the following code snippet is quite inefficient:


    var customers = (from cus in _context.Customers
                    where cus.CustomerID == i_customerId
                    select cus);
    if (customers.Count() == 1)
    {
        o_customer = customers.Single<Customer>();
    }
    else
    {
        o_customer = null;
    }

It turns out that even though the expression does not change between the call to customers.Count() and customers.Single<Customer>(), they will actually cause two calls to the Database. I had mistakenly assumed that the result would be cached as there was no change to the “query”.

By using the SingleOrDefault<T>() function that is now available in EF 2.0 (through IQueryable<T>) we actually save on the round trip.


    o_customer = (from cus in _context.Customers
                    where cus.CustomerID == i_customerId
                    select cus).SingleOrDefault<Customer>();

Something to bear in mind when working with IQueryable<T>.

a2dbm5vn79

  • Share/Bookmark

Finally! I’ve been itching to get into the latest incarnation of the EF for a while now and finally I had the opportunity to take it around the block (kick the tires and generally rough it up). My main interest in EF 2.0 was the supposed support for Unit Testing and the improvements on using POCO to map to the Data Model.

I have to admit, although I liked EF 1.0 when I first started using it, one of my biggest bug bears was the fact that you had to “disconnect” your entities before you could really work with them outside the context (no pun intended) of the Entity Framework. I was also quite miffed when I discovered there was no easy way to mock the underlying data layer so I ended up with code like this:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        m_customerRepository.Load(i_customerId, out o_customer);

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

In this case, m_customerRepository is the injected ICustomerRepository instance. When we look at the implementation of the actual data layer class (which does not get tested by the Unit Test, we find that inside the Load method we have the following:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out BaseCustomer o_customer)
    {
        Customer customer = (CustomerSet.Where(cust => !string.IsNullOrEmpty(cust.CustomerID) &&
                                                       cust.CustomerID == i_customerId)).First();
        if (customer != null)
        {
            o_customer = new BaseCustomer()
                             {
                                 Address = customer.Address,
                                 City = customer.City,
                                 CompanyName = customer.CompanyName,
                                 ContactName = customer.ContactName,
                                 ContactTitle = customer.ContactTitle,
                                 Country = customer.Country,
                                 CustomerID = customer.CustomerID,
                                 Fax = customer.Fax,
                                 Phone = customer.Phone,
                                 PostalCode = customer.PostalCode,
                                 Region = customer.Region
                             };
        }
        else
        {
            o_customer = null;
        }
    }

Not the best way of doing things, that is for sure! In fact it is downright ugly (IMHO). So when I heard that there were improvements to the EF for .NET 4.0, especially in the area of Unit Testing I was curious to say the least. As I delved in deeper I started finding more and more things that made it more attractive to my style of development. For example one of the beauties of EF 2.0 is the fact that you can remove the CustomTool that generates the entity classes that are bound to the data model (through the edmx file). When you do this, you effectively get rid of the code generation for the EF instance that you have loaded in your project. There are some excellent examples (and walkthroughs available) from the ADO.NET Team blog:

POCO in Entity Framework : Part 1 – The Experience (excellent walkthrough on removing the CustomTool)

POCO in Entity Framework : Part 2 – Complex Types, Deferred Loading and Explicit Loading

POCO in Entity Framework : Part 3 – Change Tracking with POCO

So now what? Great! So now I can use my POCO to update the Data Model. But I still hadn’t found out how to do true unit testing with DI and mocking? I was quite flummoxed until I realized (with a helpful pointer from a friend at Microsoft – thanks Jason) that the answer was staring me in the face:

“Can’t you create a mock class that derives from IObjectSet instance yourself, or is there a problem doing that?”

Well yes, I did have a problem with that – it meant that I would have to write more code. I was naively hoping to have something like:


List<Customer> cusList = TestHelper.CreateCustomerList();
IObjectSet<Customer> context = cusList.AsObjectSet();

So I was being lazy… I guess that, with each version of .NET, I had become more and more accustomed to so much being done for me that stumbling across something as “simple” as creating an AsObjectSet() function that was not available was bit of a shock. More so when you look at what IS available on a List<entity> method / property list.

At first I contented myself with just doing what was obvious – create a mock class that inherited from IObjectSet<Customer>, before I realized (with another push from Jason) that I could make it more generic and have a MockObjectSet<T> class:


    internal class MockObjectSet<T> : IObjectSet<T>
        where T : class
    {
        public MockObjectSet(List<T> entityList)
        {
            if (entityList == null)
            {
                throw new ArgumentNullException("entityList");
            }
            else
            {
                _repository = entityList.ToList();
            }
        }

        IList<T> _repository;

        #region IObjectSet<T> Members

        public void AddObject(T entity)
        {
            _repository.Add(entity);
        }

        public void Attach(T entity)
        {
            this.AddObject(entity);
        }

        public void DeleteObject(T entity)
        {
            _repository.Remove(entity);
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return _repository.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _repository.GetEnumerator();
        }

        #endregion

        #region IQueryable Members

        public Type ElementType
        {
            get { return typeof(T); }
        }

        public System.Linq.Expressions.Expression Expression
        {
            get { return _repository.AsQueryable<T>().Expression; }
        }

        public IQueryProvider Provider
        {
            get { return _repository.AsQueryable<T>().Provider; }
        }

        #endregion
    }

It is important to note here that the TestHelper.CreateCustomerList() function has several overrides and returns a List<Customer> filled with dummy data.

After playing around a bit I realized that I could actually just create an Extension Method that would create an instance of the mock CustomerSet and therefore I could call it from within my Unit Test code. The Extension Method looks like this:


    public static class ObjectSetExtension
    {
        public static IObjectSet<T> AsObjectSet<T>(this List<T> entities) where T : class
        {
            return new MockObjectSet<T>(entities);
        }
    }

Now if we revisit the unit test code, we get the following:


        [TestMethod]
        public void TestLoadValidCustomerContactNameWithSurname()
        {
            // Arrange
            // Create the stub instance
            INorthwindContext context = MockRepository.GenerateStub<INorthwindContext>();
            // Create the dummy data
            const string customerId = "555";
            const string contactName = "James Person";
            IObjectSet<Customer> customers = TestHelper.CreateCustomerList(contactName, customerId).AsObjectSet();

            // declare the dummy instance we are going to use
            Customer loadedCustomer;

            // Explicitly state how the stubs should behave
            context.Stub(stub => stub.Customers).Return(customers);

            // Create a real instance of the CustomerManager that we want to put under test
            Managers.CustomerManager manager = new Managers.CustomerManager(context);

            // Act
            manager.Load(customerId, out loadedCustomer);

            // Assert
            context.AssertWasCalled(stub => { var temp = stub.Customers; });
            // Check the expected nature of the dummy intance
            Assert.IsNotNull(loadedCustomer);
            Assert.IsNotNull(loadedCustomer.ContactName);
            Assert.IsTrue(loadedCustomer.ContactName == "James PERSON");
        }

If we compare the two managers again (the manager that I had created in a previous blog posting depended on EF 1.0), we will see that the EF 2.0 instance actually contains lambda expressions to do the queries.

EF 1.0:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        m_customerRepository.Load(i_customerId, out o_customer);

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

EF 2.0:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        var customers = (from cus in _context.Customers
                         where cus.CustomerID == i_customerId
                         select cus);
        if (customers.Count() == 1)
        {
            o_customer = customers.Single<Customer>();
        }
        else
        {
            o_customer = null;
        }

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

In the second code, snippet, because I am calling straight to an instance of IObjectSet<Customer>, it could either be my mocked one or the actual Entity Framework instance, which looks like this (thanks to POCO binding):


    public class NorthwindContext : ObjectContext, INorthwindContext
    {

        public NorthwindContext()
            : base("name=NorthwindEntities", "NorthwindEntities")
        {
        }

        private ObjectSet<Order> _orders;
        private ObjectSet<Employee> _employees;
        private ObjectSet<Customer> _customers;

        #region INorthwindContext Members

        IObjectSet<Employee> INorthwindContext.Employees
        {
            get { return _employees ?? (_employees = CreateObjectSet<Employee>()); }
        }

        IObjectSet<Customer> INorthwindContext.Customers
        {
            get { return _customers ?? (_customers = CreateObjectSet<Customer>()); }
        }

        IObjectSet<Order> INorthwindContext.Orders
        {
            get { return _orders ?? (_orders = CreateObjectSet<Order>()); }
        }

        #endregion
    }

This means that when I run my code coverage for the EF 2.0 version, I will be hitting the true boundary between the entity and the model, thanks to a combination of POCO and the separation of concerns brought about by IObjectSet.

Ok, so there’s no kitchen sink – what would you do with it if there was?

  • Share/Bookmark

One way to use the Entity Framework on your legacy code

Following on the DI blog posts that I have been authoring lately, I wanted to discuss one possible method of stripping out the underlying data access layer (DAL) and introduce the Entity Framework from Microsoft. My intention is to write about how you would be able to use DI when introducing the new DAL.

Starting with what we already have.

In many cases there will be some form of data access layer manager class that will act as the proxy to client code when performing the request to the database and translating the returned query into “code entities”. This would be the ideal place to start the transition (obviously). Capitalizing on our earlier example of the NorthWind database, let’s assume that we have the following classes:

Base Classes

As you will see, we have two DAL related classes; EmployeeRepository and CustomerRepository. Both of these expose typical CRUD methods that we will refactor into interfaces. Once the principal methods have been extracted into interfaces then we can create the new client facing entities that will provide access to the DAL via the appropriate methods and functions:

Manager Classes

As you can see from the class diagram, each of the manager classes has two constructors; the first (parameter-less) constructor is the default and contains no code except for calling into the second constructor; the second (single parameter) constructor contains the assignation of a member variable to the associated repository interface:

  1. /// <summary>
  2.     /// Parameterless (Default) constructor
  3.     /// </summary>
  4.     public EmployeeDataManager() : this(null)
  5.     {
  6.     }
  7.  
  8.     /// <summary>
  9.     /// Parameterized constructor
  10.     /// </summary>
  11.     /// <param name="i_repository">The IEmployeeRepository instance to
  12.     /// be used.</param>
  13.     internal EmployeeDataManager(IEmployeeRepository i_repository)
  14.     {
  15.         m_repository = i_repository;
  16.     }

One important note to make and something that may or may not seem strange is the definition of the second constructor as internal as opposed to public. If you remember from a previous post, by defining the second constructor as internal and then exposing it only to the unit tests (via the assembly attribute InternalsVisibleTo) – this way when coding the clients of the manager, we will not place the onus of instantiating a repository on the client (unless you wish to do so).

Later on, once we have the DAL utilizing the Entity Framework in place, we can extend the assignation of the repository interface to also include the instantiation of our default DAL.

Incorporating the Entity Framework

The first stage is to create a suitable assembly where the Entity Framework related classes will reside and be referenced from. Therefore we could create an entity access assembly:

Pre Entity Framework

Now we can go through the steps of incorporating the Entity Framework:

  1. In the EntityAccess project, add a new “ADO.Net Entity Data Model” item:

    Stage 1
  2. In this example we want to create the model contents from the actual DB instance:

    Stage 2
  3. The next window of the Entity Data Model Wizard specifies the Data Connection that will be used. Depending on your requirements this will vary from situation to situation:

    Stage 3
  4. In this case we will create a new one for our purposes; click the “New Connection…” button to display the Connection Properties dialog (Fill-out the fields as appropriate to your purposes) and select the Server and the Database instance:

    Stage 4
  5. Once the Connection Properties have been configured, the appropriate information will appear:

    Stage 5
  6. Clicking the “Next >” button will take us to the “Choose Your Database Objects” window, where we can select the tables that we are interested in (seeing as it is such a small schema, we will select all tables in this example):
    Stage 6
  7. Once we have clicked on the “Finish” button the associated edmx file (XML file that defines an Entity Data Model) and it’s associated code behind have been generated:
    Stage 7 - a


    Test Stubs Dialog
  8. For consistency reasons (and personal preference) I normally change the default entity naming convention as follows, renaming the pluralized to singular:
    Stage 8 - a

    becomes

    Stage 8 - b


    Stage 8 - c

Now that we have added the Entity Framework into the solution we can set about incorporating the use of the appropriate repository interfaces (ICustomerRepository and IEmplyeeRepository).

Delving into the code generated when the Entity Data Model was generated (NorthWind.Designer.cs) we find that the class is defined as partial:

  1. /// <summary>
  2.     /// There are no comments for NorthwindSQLEntities in the schema.
  3.     /// </summary>
  4.     public partial class NorthwindSQLEntities : global::System.Data.Objects.ObjectContext
  5.     {
  6.      …
  7.     }

This means that we could use the same class to implement the two interfaces we already have defined:

Stage 9 - a

Unfortunately when we attempt this method of implementing the repository interfaces we encounter the following error on the first attempt at accessing the database via the entity data model:

Stage 9 - b

With this issue raised it is easier to sub-class the Entity Data Model generated class and implement the interfaces in the child class:

Stage 9 - c

Further digging around in the auto-generated Entity Data Model reveals the different overloads for the constructor:

  1. /// <summary>
  2.     /// Initializes a new NorthwindSQLEntities object using the
  3.     /// connection string found in the ‘NorthwindSQLEntities’ section
  4.     /// of the application configuration file.
  5.     /// </summary>
  6.     public NorthwindSQLEntities() :
  7.             base("name=NorthwindSQLEntities", "NorthwindSQLEntities")
  8.     {
  9.         this.OnContextCreated();
  10.     }
  11.     /// <summary>
  12.     /// Initialize a new NorthwindSQLEntities object.
  13.     /// </summary>
  14.     public NorthwindSQLEntities(string connectionString) :
  15.             base(connectionString, "NorthwindSQLEntities")
  16.     {
  17.         this.OnContextCreated();
  18.     }
  19.     /// <summary>
  20.     /// Initialize a new NorthwindSQLEntities object.
  21.     /// </summary>
  22.     public NorthwindSQLEntities(global::System.Data.EntityClient.EntityConnection connection) :
  23.             base(connection, "NorthwindSQLEntities")
  24.     {
  25.         this.OnContextCreated();
  26.     }

With this in mind we can create a constructor that takes 4 parameters that can be used to generate the appropriate connection string:

  1. /// <summary>
  2.     /// Creates a new NorthwindEntityContext.
  3.     /// This class will be the handler for all CRUD operations
  4.     /// perfomed by the EntityAccess layer.
  5.     /// A connection is created from this constructor.
  6.     /// </summary>
  7.     public NorthwindSQLEntities(
  8.         string i_serverName,
  9.         string i_catalogName,
  10.         string i_user,
  11.         string i_pswd)
  12.             : base(BuildConnectionString(
  13.                 i_serverName,
  14.                 i_catalogName,
  15.                 i_user,
  16.                 i_pswd))
  17.         {
  18.            
  19.         }

The BuildConnectionString function would construct the appropriate connection string as follows:

  1. private static string BuildConnectionString(string i_serverName, string i_catalogName, string i_user, string i_pswd)
  2.     {
  3.         string serverName = Environment.MachineName;
  4.         if (!string.IsNullOrEmpty(i_serverName))
  5.             serverName = i_serverName;
  6.         string catalogName = "NorthwindSQL";
  7.         if (!string.IsNullOrEmpty(i_catalogName))
  8.             catalogName = i_catalogName;
  9.  
  10.         string AdoConnectionString = string.Empty;
  11.         if (!string.IsNullOrEmpty(i_user))
  12.         {
  13.             AdoConnectionString = string.Format(
  14.             "Data Source={0};Initial Catalog={1};Integrated Security=False;MultipleActiveResultSets=True;Uid={2};Pwd={3}",
  15.             serverName, catalogName, i_user, i_pswd);
  16.         }
  17.         else
  18.         {
  19.             AdoConnectionString = string.Format(
  20.                 "Data Source={0};Initial Catalog={1};Integrated Security=True;MultipleActiveResultSets=True",
  21.                 serverName, catalogName);
  22.         }
  23.         return string.Format(
  24.             "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\";{1}\";",
  25.             EntityModelName, AdoConnectionString);
  26.     }

The Entity Framework provides the appropriate mapping between the Storage Model (Database) and the Conceptual Model (entities), however, in order to be able to implement Dependency Injection we need to maintain (or create) a disconnected set of implementation classes that are agnostic to the underlying repository (be it Entity Framework or any other data access model, such as NHibernate, etc.).

Therefore the CRUD methods that we have exposed through our original interfaces, in the Entity Framework domain, would provide a certain amount of “translation” from the disconnected entity type to the “connected” (EDM) type:

  1. using BaseCustomer = DiDemo.BaseData.Entities.Customer;
  2. using DiDemo.BaseData.Interfaces;
  3.  
  4. namespace DiDemo.EntityAccess
  5. {
  6.     public partial class NorthwindSQLEntities :
  7.         ICustomerRepository, IEmployeeRepository
  8.     {
  9.     /// <summary>
  10.     /// Insert a new Customer instance into the Database.
  11.     /// </summary>
  12.     /// <param name="i_customer">
  13.     /// The Customer instance to be inserted.
  14.     /// </param>
  15.     public void Insert(BaseCustomer i_customer)
  16.     {
  17.         Customer customer = new Customer()
  18.             {
  19.                 Address = i_customer.Address,
  20.                 City = i_customer.City,
  21.                 CompanyName = i_customer.CompanyName,
  22.                 ContactName = i_customer.ContactName,
  23.                 ContactTitle = i_customer.ContactTitle,
  24.                 Country = i_customer.Country,
  25.                 CustomerID = i_customer.CustomerID,
  26.                 Fax = i_customer.Fax,
  27.                 Orders = new EntityCollection<Order>(),
  28.                 Phone = i_customer.Phone,
  29.                 PostalCode = i_customer.PostalCode,
  30.                 Region = i_customer.Region
  31.             };
  32.         this.AddToCustomerSet(customer);
  33.         this.SaveChanges();
  34.     }

Unit Testing

Now that we have the underlying Data Access Layer sorted out, time to move on to the reason for this blog posting – Unit Testing.

Obviously the very basic CRUD methods and functions do not provide any head banging issues when it comes to unit testing, however, suppose there a function returned an IQueryable instance? It could possibly be conceived that such a method existed as follows:

  1. /// <summary>
  2.     /// Returns a List of Customer instances
  3.     /// </summary>
  4.     /// <returns>List containing all Customer instances.</returns>
  5.     public List<BaseCustomer> LoadAllCustomers()
  6.     {
  7.         return Query_LoadAllCustomers().ToList();
  8.     }
  9.  
  10.     /// <summary>
  11.     /// Returns an IQueryable for the Customers entity set.
  12.     /// </summary>
  13.     /// <returns>IQueryable of the customer enitity set.</returns>
  14.     public IQueryable<BaseCustomer> Query_LoadAllCustomers()
  15.     {
  16.         return (from query in CustomerSet
  17.                 select new BaseCustomer()
  18.                 {
  19.                     Address = query.Address,
  20.                     City = query.City,
  21.                     CompanyName = query.CompanyName,
  22.                     ContactName = query.ContactName,
  23.                     ContactTitle = query.ContactTitle,
  24.                     Country = query.Country,
  25.                     CustomerID = query.CustomerID,
  26.                     Fax = query.Fax,
  27.                     Phone = query.Phone,
  28.                     PostalCode = query.PostalCode,
  29.                     Region = query.Region
  30.                 });
  31.     }

Surprisingly enough it is not that difficult to create the unit test for such a method in the Manager class. Seeing as we have successfully done the dependency injection prior to creating the entity framework related classes, all we are actually doing is writing the test for the manager class by mocking the repository interface:

  1. [TestMethod]
  2.     public void TestIQueryableOnEntity()
  3.     {
  4.         // Create the mock instance
  5.         IEmployeeRepository eConnect = m_mockRepository.DynamicMock<IEmployeeRepository>();
  6.  
  7.         // Here we create an actual instance
  8.         IQueryable<Employee> mockedCollection;
  9.  
  10.         // Setup a dummy list that will be filtered, queried, etc
  11.         List<Employee> employeeList = CreateEmployeList();
  12.         mockedCollection = employeeList.AsQueryable();
  13.  
  14.         // Now we set our expectations
  15.         Expect.Call(eConnect.Query_LoadAllEmployees()).Return(mockedCollection);
  16.  
  17.         // Replay our expectations
  18.         m_mockRepository.ReplayAll();
  19.  
  20.         // Create a real instance of the EmloyeeConnector that we want to put under test
  21.         EmployeeManager manager = new EmployeeManager(eConnect);
  22.  
  23.         List<Employee> employees = manager.Query_LoadAllEmployees().ToList();
  24.  
  25.         Assert.IsNotNull(employees);
  26.  
  27.         Assert.IsTrue(employees.Count == employeeList.Count);
  28.     }

The secret is in the AsQueryable method on the List instance. By doing this we can simulate the behavior of the IQueryable function on our Entity Data Model.

  • Share/Bookmark