Posts tagged Entity Framework

Why Unit Test without Mocking your EF Repository

Every once and a while I get a fair amount of flak about how I unit test my services. I’m a firm believer in the Onion Architecture and Repository Patterns and the techniques developed at Online Advisors for implementing those patterns are still better then any other implementation I’ve seen.

Y87zIwvThe repository itself is generic and thin. You can see an implementation on this GitHub page. With the underlying data store implementation hidden behind a generic interface that makes it very easy to mock the calls to the database, but should you?

Any Unit Testing purist will tell you that Unit Testing is only testing one small, isolated, functional unit of code. When that unit of code go out of scope it needs to be mocked. This is all well and good, and I do a fair amount of testing like this. But then Entity Framework Code First and automatic migrations came along, coupled with SQLCE or LocalDB why mock your repository?

When my repository method is generic (i.e. a Get, Save, Delete) there is no real logic in there. But when I test it I gain the added benefit of verify that data going to the database and back is correct. Additionally using the Seed method of Entity Framework it’s very easy to scaffold in test data that can be utilized by the test.

Anyone who’s mocked complex data structures knows your basically writing a lot of that by hand, or storing it in a file and deserializing it to be served up to tests. If your going though that trouble, then why not just use EF, Code First, Automatic Migrations and Seeding? It really is a time saving once you got the data in the seed statement.

Additionally it’s helped me find concurrency and data access issues. Because of how unit tests are executed using a lightweight SQL instance I was trace down race conditions and slow LINQ statements. None of which would have been possible by just testing the service or logic layer in isolation.

When I test this way I still call it unit testing. The way it gets the data, either through an In-Memory array, Mock or LocalDB is not what’s being tested. As long as my repository method itself has no code or logic it will be side effect free.

This isn’t without it’s faults and it’s not perfect. Based on their very nature SQLCE and LocalDB are very lightweight version of SQL Server. This means they can’t perform the way normal SQL does, operate in the same way or even use some of the same data types. For example SQLCE doesn’t support the Geo data type.

So it may not be perfect for every scenario or database. But if it’s an option, will be side effect free and won’t cause interdependency issues between tests then really is the difference between that and Mocking? Besides the fact that your exercising more of your code base?

Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).

Entity Framework Seed AddOrUpdate Issue

, I’ve been using EF Code First since it was in CTP and hopped onto manual migrations bandwagon as soon as I could. I’m still on the bandwagon by the way and we use EF Code First and Manual Migrations to manage production (Microsoft Azure SQL), test and dev deployments of Resgrid. But this is not to say there aren’t issues, one of the big ones has been with EF’s Seed method.

entity_imageFor the uninitiated, EF has a method called Seed that’s part of the code configuration when your using EF Migrations (Automatic and Manual). This method allows EF to ensure the baseline required data is inside your database. For example type tables, test users\companies, etc. Every time EF starts up it runs through the Seed method to ensure your baseline data is correct. The recommend method for this is AddOrUpdate. Which allows you to set a unique key (or compound/complex key) and insert the record of it’s missing or update it if it’s changed (i.e. you fixed a spelling mistake in the type name field). Pretty cool huh?

Boy oh boy can that bite you in the ass. I’ve had seed records inserted thousands of times due to AddOrUpdate. The issue seems to arise when you use the following syntax:

context.Customers.AddOrUpdate(a => a.CustomerId,
    new Customer
    {
        CustomerId = 1,
        Name = "Test Customer",
        ShowWelcome = true,
        TimeZone = "Eastern Standard Time"
    });

CustomerId is a Primary Key, most of the time this will insert just fine. But then there are the fun times, where Customer won’t have an Id of 1, but instead 2, or 3 or 100. EF just gives up, for whatever reason and silently inserts a record that you didn’t want into the the table and can keep inserting it. This seems to happen when you have multiple inserts of the same record type.

In addition to having many records inserted you can get inserts completely out of order. Take for example this code.

context.Customers.AddOrUpdate(a => a.CustomerId,
    new Customer
    {
        CustomerId = 1,
        Name = "Test Customer",
        ShowWelcome = true,
        RefId = "50DEC5DB-2612-4D6A-97E3-2F04B7228C85",
        TimeZone = "Eastern Standard Time"
    },
    new Customer
    {
        CustomerId = 2,
        Name = "Test Customer 2",
        ShowWelcome = true,
        RefId = "AFA1E979-FCA9-417B-A03D-69C0588FAD71",
        TimeZone = "Pacific Standard Time"
    },
    new Customer
    {
        CustomerId = 3,
        Name = "Test Customer 3",
        ShowWelcome = true,
        RefId = "1AA0DCF8-4220-4C86-A10B-B6F8B3C0CA44",
        TimeZone = "Central Standard Time"
    }};

Based on it we would expect Test Customers to be record 1, Test Customer 2 to be record 2 and Test Customer 3 to be record 3. Would you believe me if I told you Test Customer 3 got CustomerId 1, Test Customer got CustomerId 2 and Test Customer 2 got CustomerId 3. WTF?!?!

Some solutions involve using a non-Primary Key field and instead focusing on another field in this example Name, or a combination like Name and Timezone (obviously I wouldn’t use Name and Timezone, you would want to use truly unique values). The syntax for a compound key looks like this:

context.Customers.AddOrUpdate(a => new { a.Name, a.SSN },
    new Customer
    {
        Name = "Test Customer",
        SSN = "555-55-5555",
        ShowWelcome = true,
        RefId = "50DEC5DB-2612-4D6A-97E3-2F04B7228C85",
        TimeZone = "Eastern Standard Time"
    }};

So the issue seems that before the end of the Seed method (for at least the mix up of the inserted objects) it re’orders them internal before they are sent to the server to be executed.

How did I get around this? I added context.SaveChanges(); in between each of the inserts that were causing issues.

context.Customers.AddOrUpdate(a => a.CustomerId,
    new Customer
    {
        CustomerId = 1,
        Name = "Test Customer",
        ShowWelcome = true,
        RefId = "50DEC5DB-2612-4D6A-97E3-2F04B7228C85",
        TimeZone = "Eastern Standard Time"
    }};
    
context.SaveChanges();    

context.Customers.AddOrUpdate(a => a.CustomerId,
    new Customer
    {
        CustomerId = 2,
        Name = "Test Customer 2",
        ShowWelcome = true,
        RefId = "AFA1E979-FCA9-417B-A03D-69C0588FAD71",
        TimeZone = "Pacific Standard Time"
    }};
    
context.SaveChanges();
    
context.Customers.AddOrUpdate(a => a.CustomerId,
    new Customer
    {
        CustomerId = 3,
        Name = "Test Customer 3",
        ShowWelcome = true,
        RefId = "1AA0DCF8-4220-4C86-A10B-B6F8B3C0CA44",
        TimeZone = "Central Standard Time"
    }};
    
context.SaveChanges();

Now my records are created properly. Somewhere in the chain of adding more objects to the database these referenced objects get re-ordered in the execution chain.

Entity Framework’s Change Tracking is Jenga for ORM’s

I recently spent an entire evening tracking down a crazy Entity Framework error:

"The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted."

Oh now that’s a classic Entity Framework error. The problem is that the operation I was performing had no changes to the relationships. I was just setting some data on the object and saving it back. Everything else on the site worked, I could delete, add and update DB objects everywhere, it was just this one page, but why? So began a 6 hour crown and coke fueled debugging session where I had to “git reset” 4 times.

jenga

Entity Framework’s change tracking system is very complicated and far reaching. Operations that you perform on change tracked objects can have a big impact in different areas. MSDN has a good area on Change Tracking for POCO objects to get an overview. And there is a good answer on Stack Overflow on it as well.

I eventually tracked down the offending code, but the kicker, it has been working in the system for over 6 months! So why now all of a sudden did I get this error message? I would say that change tracking is a house of cards and that can be true, one issue or one mistake and it can all fall down, but really Entity Framework and it’s Change Tracking is a game of Jenga, something you did early can cause a catastrophic failure latter on.

Lets look at the offending code, that was almost completely separate from where I was getting the Entity Framework exception above:

public List<DepartmentGroup> GetAllGroupsForDepartment(int departmentId)
{
    List<DepartmentGroup> departmentGroups = GetAllGroupsForDepartmentUnlimited(departmentId);

    // Remove all Disabled or Hidden Users
    foreach (var dg in departmentGroups)
    {
         dg.Members = (from m in dg.Members
                       where !_departmentsService.IsUserDisabled(m.UserId) && !_departmentsService.IsUserHidden(m.UserId)
                       select m).ToList();
    }

    return departmentGroups;
}

The code above get’s all the DepartmentGroup’s for a Department, pretty simple. In Resgrid you can hide or disable users, so they won’t appear in parts of the system. So we remove them from the list of members and continue. This is where the issue lies, because we are removing Members, which was populated by Entity Framework and all change tracked it assumed that we wanted to delete the members that didn’t make back into the Members list. Leaving their DepartmentGroup reference null and causing the error when we tried to submit changes.

This from my experiences with Resgrid which is a cloud service company, SaaS deployed on Microsoft Azure, providing logistics and management tools to first responder organizations like volunteer fire, career fire, EMS, search and rescue, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).

Like I said before this code has been in the system for 6 months without issue. But why did it break now and how did that code affect a completely unrelated part of the system? Normally in the app, either via the API or the web site, calls like this live in isolation and the context is scoped to the current request, giving us a nice Unit of Work Pattern. Every time that method got called it’s affects on the context were short lived and isolated.

We recently added a new feature to the Edit Profile pages where you could set a person’s group, so to get the departments groups we called that method, in the POST of the controller we re-get them to re-populate the view model. This is where we ran into the issue, change tracking detected the removal and when we tried to update our unrelated object the error was thrown.

What I wish is that Entity Framework would allow us to figure our what SubmitChanges() was trying to do, this would have made the debugging process far easier. Instead it was hours upon hours of work and was only found when I started commenting stuff out and removing it.

So if you are getting the error above and your not removing child objects from the database take a look at other operations your performing in the scope (this works well in your using a Unit of Work pattern). As a practice don’t remove objects from a change tracked collection unless you want to remove the object from the db, instead remove change tracking or spin the result into a new collection.

Go to Top