Skip to content
Adam O'Neil edited this page Jun 20, 2022 · 26 revisions

Why Dapper.CX?

Note I'm not updating this anymore, and instead am using Dapper.Repository

There are a number of Dapper-based CRUD libraries out there with large communities: Dapper-Extensions, Dapper.FastCRUD, Dapper.SimpleCRUD, probably others. I made my own because I'm a data access nut from way back, and I have an enduring obsession with this problem space. I really couldn't say whether the world needs another Crud library, I simply enjoy working on this.

One differentiator I believe Dapper.CX has is a SaveAsync method that automatically inserts or updates based on the model state. Dapper.CX has explicit InsertAsync and UpdateAsync methods as well, but other libraries seem to require that you implement the insert-update branching yourself.

Similar to SaveAsync, I offer a MergeAsync method that finds an existing record by its combined key properties rather than an Id value before saving. This is handy for cases where you don't have an Id value in scope on a model entity, but want to perform an insert or update as if you did.

Another thing I like about Dapper.CX is ChangeTracker. A ChangeTracker is used as an optional argument with SaveAsync, MergeAsync, or UpdateAsync to result in an UPDATE statement that affects modified properties of a model class only. This gives me greater confidence that my crud operations aren't touching columns unnecessarily during updates.

My other ORM project was Postulate. I'd started to feel like it was getting too complicated, and I saw a need to break it into two packages -- a CRUD library and a query library. The query library spin-off is Dapper.QX. With Dapper.CX, I wanted to go back to basics, simplify, and commit to a pure POCO approach. I'd gotten in the habit of building "fat" model classes with all kinds of behaviors and logic (permission checks, validation, multi-tenant isolation). I used to bake this into my model classes as built-in dependencies, but now I offer all these "fat" features as opt-in interfaces, now defined in a separate, very lightweight package AO.Models. Learn more about my suggestions for model classes here.

What About Entity Framework?

My feeling is that Entity Framework is not simple enough, and is too easy to do wrong. I also find migrations pretty painful. (I approach migrations using my ModelSync library and app.) In my view, productivity and simplicity are king. I feel that EF trades simplicity for abstraction. I feel that any application that already depends on a relational database should embrace it, much in the way web developers eventually embraced HTTP and (largely) gave up on abstractions like ASP.NET WebForms meant to hide it. Of course, some abstraction is a good thing. That's why we have model classes, and why we shouldn't have inline SQL for CRUD operations. That's why CRUD libraries like Dapper.CX and the others listed above exist.

There may come a day when relational databases are obsolete, but I feel that's a long way off. There are great things happening with Cosmos DB, for instance. I do look forward to a time when we don't need any kind of ORM layer, and something like Cosmos DB does everything better than relational databases today. I think that is still a ways off, though. Therefore, in the meantime I say embrace your RDBMS if you're using one, and use a straightforward CRUD library for data access.

PS. My feelings about general-purpose queries and Linq are a different discussion. That's why I have my Dapper.QX library, since I don't believe Linq works as a total SQL replacement. I love and use Linq for many things, just not as a total SQL replacement.