Yesterday I have a nice, interesting chat with someone I just met. In those discussion about software development and technology, he asks whether I use Entity Framework for my current architecture or not. I was saying it clearly, I’m not using any kind of ORM nor develop one myself. Before I continue, I want to clarify that I’m not hating the ORM or anything. With my current skill and experience, I’m just not ready for the edge cases (or to be precise, corner cases) that can occur when using ORM.
When asked with such question, I had hard time to give reasons about it. One of the reason is that there will be hard to find developer with expert knowledge of particular ORM, rather than expert knowledge in stored procedure-based command execution. The other is, ORM has leaky abstraction. I’m not saying that other than ORM or any tools that I used until now has none leaky abstraction, but I don’t think it’s worth the effort to do the workaround for ORM’s corner cases, compared to matured, traditional stored procedure and query.
Not all Linq expression is supported to be translated into sql
This statement is primarily based on article from Mark Seeman: IQueryable is a leaky abstraction. In that article, he state that there are some unsupported expression exposed from IQueryable. He states that the unsupported expression itself violates LSP. Moreover, quick search at google shows some stackoverflow questions asking for the NotSupportedException. One of them shows inconsistency with linq2sql, where when someone use string.Contains the ORM throws exception meanwhile using join the expression executed. Another post says the same about EF.
So as we can see, the IQueryable interface used by ORM give us false guarantee or false positive, just because the code compiles but produce runtime exception later. The same case can also happen with SqlCommand. However the error is clear, that it’s either: 1) different sql data type provided to SqlParameter, 2) incorrect parameter provided, 3) wrong sql syntax. However it is the opposite with in-memory IEnumerable lambda/linq, where the expression is fully supported.
Now we have additional step to measure sql performance
ORM translate query expression into sql queries. If you do not master the specific ORM, you won’t know what kind of sql query produced. Moreover, different ORM produced different query. Now if we concern about the sql performance, we have 2 steps to do. First step is to determine which exactly sql query resulted from ORM, while the other is real measurement with indexes, plan, etc.
Common case is N+1 selects issue with ORM in which handled differently by different ORM, and impact the performance.
Data annotation breaks POCO and SRP
This is specific to EF with data annotation. If you prefer to use fluent api, great on you.
Data annotation break POCO, nuff said. Based on wikipedia, POCO or Plain Old CLR Object is simple object which does not have any dependency to other framework/plugin/tools. Even Serializable and XmlIgnore data annotation breaks POCO, and I’ve already stated that cluttering the class to make it xml serializable is usually bad.
It also breaks SRP. Now that your POCO class has another responsible coupled with it. The additional responsible is handling the way ORM mapping from table to the object. It isn’t wrong, but it’s not clean. The worst part is, you need to modify your POCO class to meet mapping requirement.
The original underlying structure of database is relational
Original post by Martin Fowler states that the root of main problem is the difference in underlying structure between application (OOP) and database (RDBMS). The way they handle relations is different and the way they are processing data is also different. Even Jeff Atwood also said that the ORM problem will be clear by either you remove the “object” aspect or “relational” aspect, either by following table structure in application or using ODBMS. ODBMS is great, but it also has cons compared to RDBMS.
When and how many times the query being executed?
I don’t know how good you are with IQueryable abstraction. However even with in memory IEnumerable, there are many times i’ve caught with bug where the iterator is executed multiple times, resulting in inconsistent data properties and increasing cost. With IEnumerable / IQueryable ORM, I don’t know when and how many times exactly the sql query being executed, and it can impact performance considerably.
Additional sources where they have documented the issue
These sources are more like general statements or even the detailed technical one, so I don’t follow it one by one. But it shows you the lists of current problem faced by ORM.
As a developer / architect that concern with clean code, consistency, coding standard and convention, I don’t think that ORM will suit me. There is simply too many corner cases that can’t be handled by current ORM, and I don’t like (and don’t have time) to document every cases that cannot be handled, and the solution or workaround. It’ll be a pain to teach to the new developer your ORM case handling standard. Moreover it can cause you more time to fix the problem caused by the ORM rather than it’s benefit.
However if you find yourself confident that you can handle the corner cases, or if you exactly know that the application won’t face those corner case with ORM, then it’s a great tool to be used.