Why I Dislike Entity Framework for REST API Development
Tags: entityframework, dotnet, database, programming
Published: 2022-09-19 02:39:17

> Originally published @ [hasnode.dev](https://webjose.hashnode.dev/why-i-dislike-entity-framework-for-rest-api-development).

# Preface

I have been a backend developer for easily 14 years, all of them in .Net, whatever version was on at the time.  During the better part of those 14 years I have gone through all the so-called goodies **Entity Framework** provides, from related properties and lazy loading to data model change tracking, database-first and code-first.  Care to guess how many times I felt satisfied about how having all that at my disposal cut my go-to-production time?  Zero.

I guess that at this point it is fair to set some perspective:  I have always worked for mutinational enterprises, such as *Hewlett-Packard*, *Procter & Gamble*, *IBM*, etc. and have had similar customers, including *AT&T* briefly.  The projects these companies usually need are not standard.  Not in at least 50% of their requirements.  Back 14 years ago, I used to design and code entire systems for *P&G* from waterfall documents, meaning complete project, from start to finish, all in one go, no sprints, no nothing.  Zero agile, all waterfall.  Not once in those projects, listen carefully, **NOT ONCE** did I finish a single project where the so-called features of **Entity Framework** did not trip me somehow.

Once lazy loading did not work for me and I was terrified because I was pressed for time.  The problem was that the SQL connection object was being disposed before I was needing the data.  Bottomline:  Lazy loading to the trash.

Database-first approach saves you time with models, you say.  Yes, and also create big weird, not-easily maintainable classes where I can do little to no changes or tweaks.  So code first?  Don't make me laugh.  I have always needed non-standard, out-of-the-beginners-box T-SQL for these big enterprises' databases.  So bye bye you too, ultimately-useless feature.

And I have stories for most of the mayor "great features" of Entity Framework.  Sure, I was young and naive, and having skipped Computer Science and learned all I know by myself (because I originally studied Chemical Engineering), I did not fully understand where the problem relied.  I could not pinpoint why I continued to have the issues I was having.

# My Major Discovery:  RAD Tools

There was this thing I had heard of from time to time, **RAD Tools**.  **RAD** stands for **Rapid Application Development**, and basically they exist for the lesser developers.  If you are one of those, I mean no disrespect, and I say this with you in my heart:  *STOP USING RAD TOOLS*.  Most of them are there to lure you towards something else.

What do I mean?  I will explain right now in the context of **Entity Framework**.  Microsoft and many other RAD-tool providers use RAD tools to lure you towards their paid products or to gain you on their side somehow.  **EF** is in itself a RAD-tool when you use automatic modeling creation with the database-first approach, as example here.

Another data-related example:

> "Look!", they say, "a SqlObjectDataSource component for your Windows Forms data-bound controls.  Just drop it on your form, make the connection string, select a Table, pick the ID and the text columns and voilá!, you have now filled your combo box!"

First project I tried it?  By the 4th control in need of data it could not fulfill its obligation.

Long story short:  I have always had to read A LOT of hacks and how-to tweaks to get around problems that aren't really that big of a problem, just to continue to use a RAD tool.  With **EF** (and other RAD tools) I had to learn a lot to make things work.  The cure was always more painful than the illness.

So I then stopped using **EF** altogether and started using pure ADO.net, since no other ORM's really felt adequate for one reason or another at the time.  Guys, trust me when I say this:  I felt free!  I could do any custom T-SQL, run complex and simple queries alike, connect controls and fetch data any way and at any moment I needed, could update the database reliably and with full control of the data, steps, order of steps and transactions.  It was magical.

When I did this I was finally able to actually learn how to program in layers.  If you don't see the relation, read this next sub-section.

## So RAD Tools?  Was That It?

Ok, read this section if you want to know why RAD tools do not let you create truly scalable and modular software.

The story of RAD tools is:  They cross layer boundaries for "your convenience", or so they say.  **EF**, for instance, provides the engine for data layers, but you cannot really unit test your work because you're always dependant on a database, and also creates the models for you in database-first, so you are crossing the repository layer by letting **EF** dictate your models and how they are coded.  Code-first is far less intrusive, of course.

The main RAD feature of **EF** that will always cross at least 1 boundary is its querying system, **LINQ-to-Entities**.  You are encouraged to write LINQ outside the repository boundary, automatically imposing knowledge of the underlying data structure that should have never crossed the boundary in the first place.  LINQ used like this will never let you have a properly layered system, and this is exactly how Microsoft tells you, and how teachers teach this at colleges.  Unlearn all this.

Let's quickly jump to ASP.Net controllers:  RAD tool there is the `ModelState.IsValid()` you see in a lot of controller samples out there, including Microsoft's MSDN.  Guess what?  Layer crossing.  The sole responsibility of a controller is to translate data from and to the HTTP protocol standard.  That's it.  It has no business running data validation.  None.  But it's handy, right?

So that's the story:  If you are a lesser programmer, RAD tools out there have a lot of appeal, but you'll suffer for sure when your team lead or the customer comes with some fancy requirement whose proper implementation requires code in places the RAD tools you used had hidden, again, for your so-called convenience.  You are left with a project that is closed in places where you need it open.

## How Do I Choose, Then?

Simple, first learn proper programming.  That includes SOLID and layered programming as a minimum.  Once you have acquired this knowledge, you'll have a good set of concepts that will help you jugde any library or framework you are offered.  Not all RAD tools are non-sense, and nowadays is not like my "back then".  Most frameworks and tools in this day and age are being developed with the **O** of SOLID in mind, so this is less and less a problem as time goes by.

# Enough Digressing:  The Technical Why's

In order to achieve scalable and maintainable software, it needs to follow SOLID and layered programming.  If you are careful with this, most problems will find their solution rather quickly.

As for the topic at hand, yes, you can use **EF** in a well-architectured system.  My recommendation is to turn off model tracking and use code-first and don't use the migrations feature.  There are better ways to do this, especially if we are talking microservices here.  But even like this I still dislike it.  Why, you say?

## Entity Framework Is an Implementation of the Unit Of Work Pattern

This is a good thing, but only for non-web API projects. **Unit Of Work** is good for Windows Forms, WPF or in general, desktop applications.  It has no use in RESTful systems.

In REST, you follow a strict CRUD pattern, and more importantly, you usually only work with one entity (or model) at a time.  If you read about the **Unit Of Work** pattern, you'll discover that it is useful when handling multiple models.  It produces no benefits in single-entity scenarios.  Since entity tracking is turned on by default in **EF**, the first time I got an error telling me that "there's another object being tracked for this entity ID", I almost lost my mind in rage.

In RESTful web API's, you are constantly serializing and de-serializing objects, so you don't actually care about tracking entity property changes around, which is something actually very useful in Windows Forms and WPF applications when binding data to entity collections, which I highly recommend.  In RESTful web API's we just *don't have an object being exposed to a UI where changes can be accumulated on the object to then save them in the repository (database)*.  This is not a web API thing.  **Unit Of Work** is meaningless here.

So here you are, paying in performance for a bunch of **EF** features that you don't need and some actually *interfere* with what you want to achieve.  And this, ladies and gentlemen, is probably the main reason I suffered during my early years using **EF** for enterprise-grade web projects.  I just didn't have the knowledge to understand it back then.  I hope that you, avid reader, find this information useful so you don't have to continue to suffer in your journey.  Make your journey better than mine.

# So, Go ORM-less?

Not at all.  For RESTful web API's, I highly recommend **Dapper**.  Fastest ORM in the world for .Net, beaten only by a pure ADO.net approach, and not even by much.  **Dapper** has everything your need and more to create a very well layered software system with a clear separation of concerns everywhere that also provides cool things like multiple result sets or the destructuring of joined queries into hierarchical object trees.

# So No EF in REST At All?

There's one exception I know of where you can use **EF** because it pretty much is the only option: `IQueryable<T>` extension libraries like **[Microsoft.AspNetCore.OData](https://www.nuget.org/packages/Microsoft.AspNetCore.OData).  This is very useful and handy, and follows a known standard (OData) but requires an implementation of the `IQueryable<T>` interface, and that is one thing I don't ever want to code (said implementation).

So until the day someone does an `IQueryable<T>` implementation for **Dapper**, feel free to have the 2 ORM's in your RESTful project.

# DbUp: A Replacement for Database Migrations

There's a lot to talk about when it comes to **DbUp**, but the most important aspect is that upgrade steps are not constrained to running SQL code.  They are actually defined by an interface, and therefore you can make anything that .Net can do as a database upgrade step.

In microservices, this is amazingly helpful:  Data is communicated through asynchronous channels such as queues (RabbitMQ, Kafka, ActiveMQ, etc.).  If part of your database upgrade includes data modification, you can create an upgrade step that actually broadcasts the data changes **in bulk** using a **DbUp** step.

# Final Thoughts

There's more fabric to cut here.  In microservices, being able to create a redistributable nuget package with your public models is life-saving:  One project for all microservices, and why not?, for your downstream consumers too.  This is yet one more reason to despise database-first.

Yes, all in all, you can get away with a well-structured RESTful system using **EF**, but to do this you will have suffered unnecessarily in the process.

Ok, I think I said most of what angers me about **Entity Framework**.  Do you disagree?  No problem.  We can have a healthy discussion about it.

Happy coding you all.