Most developers around me despise Entity Framework for being complicated, bloated and slow. Those people point out to light-weight micro ORMs like Dapper. I hear this all time. At work, user groups. Look, EF executes query in 631 ms while Dapper in 49 ms, why would you not want to user Dapper? I don't want to take side in this argument even though, having worked with EF for many years, I am clearly biased. I think that both frameworks have their own niche and use cases, but I was surprised what I found after swapping EF for Dapper.

We've been using my code metrics solution with EF for almost two years. Part of it is a loader that collect various metrics and saves object graph to a dozen of tables that look like this:

CodeQ-ERD

The schema is not important, but it has quite a bit of many-to-many to relationships and the loader reminds tooth ache - it runs over eight hours. We event changed our Jenkins data collection jobs to run earlier in the day to avoid running it pass midnight.

And I thought, this is going to be straightforward. Let me swap my old friend Entity Framework for Dapper. I have an integration test that wipes out database and uploads small dataset. I created a separate branch for Dapper and run that integration test in both branches. Here are the results:

EF Dapper
Lines of code 211 359
Running time, sec 36 45

Dapper turned out to be 20% slower while requiring 42% more code and the kind of code I didn't enjoy writing:

private int GetOrInsertModule(DimModule module)  
{
    var id = _connection.ExecuteScalar<int?>("SELECT ModuleId FROM dbo.DimModule WHERE Name = @name", new { module.Name });
    if (id.HasValue)
    {
        return id.Value;
    }
    else
    {
        const string sqlTemplate = @"INSERT INTO dbo.DimModule (Name, AssemblyVersion,FileVersion) VALUES (@name, @assemblyVersion, @fileVersion);
                                        SELECT SCOPE_IDENTITY();";
        id = _connection.ExecuteScalar<int>(sqlTemplate, new {module.Name, module.AssemblyVersion, module.FileVersion});
        return id ?? -1;
    }
}

And it's not so much additional code, but the repetitive code to insert modules, namespaces, types, many-to-many tables, while in EF version I could have a single generic method to take care all of them:

private static T GetOrAddEntity<T>(DbSet<T> list, T src, Func<T, bool> where) where T : class  
{
    var srcFromDb = list.Local.FirstOrDefault(where); // .Local means we'll get unsaved entities

    if (srcFromDb == null)
    {
        srcFromDb = list.FirstOrDefault(where); // Maybe it was saved before
        if (srcFromDb == null)
        {
            list.Add(src);
            return src;
        }
        else
        {
            return srcFromDb;
        }
    }
    else
    {
        return srcFromDb;
    }
}

One could argue that I should have used stored procedures. Perhaps I could shave some time, but I don't what stored procedures because they have to be deployed, parameters matched up and so on.

It is possible that I am missing something, but here are EF and Dapper versions for the reference.