My last post was a bit of a joke and I should explain why after only a few hours of playing with EF that I think it is a horrible technology. Some might say that a few hours is not enough time to completely write off a technology but I have to disagree. I spent a few hours with nHibernate and loved it. a few hours with EF and I wanted to start drinking.
First the good things about it:
- It is integrated into Visual Studio so the whole team is already able to start using it
- You can generate entities off an existing database which is convenient
- The generated items include rules about nullability, type, length, etc.
- You have MS behind it for support (<sarcasm> yippie! </sarcasm>)
- It is quick to get up and running on it
- It would appear to have first class support for mapping to stored procs (I did not try it though as I am not a fan of stored procs for the most part)
- The entities track changes made to them so that when you save you don’t have to worry about missing inserting/updating/deleting a record
Now that I have that out of the way. The bad things:
I tried to look for good things in the EF. I really did but it became obvious to me after 10 minutes that this was not the tool for me. The whole underlying idea is wrong in my opinion. The Entity Framework is really a way to bring your database up into your code (does this remind anyone of datasets?) which is 100% wrong. The database is simply a place to store the state of your business, that is all. It is up to code to define that business, it’s rules, and to persist the data between sessions/reboots/upgrades. This datacentric model that MS seems to constantly promote seems to be like saying that you should build a grocery store based on the dimensions of the shopping cart which is a totally backwards idea (but our industry has no shortage of those).
The designer is flashy and terrible. It initially impressed me that I had my model laid out infront of me but then realized that this is unnecessary, the concept of having a visual designer seems silly to me for this kind of task. For one I am a big keyboard user, if I can’t do something with a keyboard then it is not worth doing and the EF designer is mouse centric. I found it also to not be intuitive. I spent a lot of time hunting around trying to do things but it took me so long to just find/do simple things. Also if you have a database with more than a few tables you can not easily locate a table on the designer. Not being able to quickly find and change a mapping is the biggest killer for me in terms of usability. I found that anything beyond the very simplistic I had to open up the model with an xml editor and do it there which made the designer feel useless.
The framework is so not ready for the real world yet. I generated a model of an existing database and then deleted some of the tables/entities that were not required for my application. This resulted in foreign key issues in the model as it could no longer relate to that table which I could not resolve through the designer. Eventually I had to go into the raw xml of the model and delete the constraint from there. I also tried the update model functionality to re-add these tables but apparently it felt that there was nothing different between the model and the database but generated a bunch of new crap that caused more compile errors so I ended up deleting the whole model and starting over.
The framework generates some nasty looking objects for us that are not persistence ignorant. The “business” objects that the framework generates are highly coupled to the database when they are supposed to be highly coupled to OUR BUSINESS! They are implemented as partial classes so you can add business rules onto them but most developers find partial classes reduce the readability and discoverability of what is happening where in code. This leads to rules that should be in the business objects being placed elsewhere leading to architecture/reusability/consistency issues.
The amount of code that is generated is huge too. For my sample application I have 60 tables which resulted in 18,000 lines of code which is about 300 lines of code per table. In our application that uses this same database and fluent nHibernate it averages out to 24 lines per class (granted the EF is doing lots of work to track changes for us though). I found that this additional code slowed down my build more than I considered acceptable.
The lazy loading story is a complete joke. In other OR/Ms you can have child objects load from the database only when they are accessed which could save a lot of unnecessary database calls or loading logic (i.e. we can take a customer object and just go customer.Orders in our code and behind the scenes the OR/M will load the customers orders at that moment in time). In the entity framework they have deferred loading (deferred in that they will do a better job later). Using EF if you went customer.Orders you would get a null back, what you were supposed to do is go customer.Orders.Load() and then make a call to customer.Orders. This just floored me. The idea of lazy loading has been around for many many years and is simple to implement. One of the biggest issues with the EF implementation is that your business code now has to check if a collection is null and then call load on it when the business code should not care at all about state. If my code saw that customer.Orders was null it would say to me that the customer has no orders. Calling customer.Orders.Load makes zero sense to business code.
I also found it clunky to work with in code and found some unexpected results. For example calling model.Permits.Count returns me how many permits are in our database but model.Permits(0).PermitNumber throws an exception. I also found that you would explicitly have to call save changes all the time which was easy to forget:
Dim model as New Model
Dim permit As New Permit
permit.PermitNumber = 100
permit.Discipline = “B”
model.AddToPermit(permit) <-add it to the Permit table
model.SaveChanges() <-commit the change
model.SaveChanges() <-commit the change
I find always having this unit of work idea a bit of a pain myself, especially on a simple application. In more complicated persistence scenarios it could be a nice feature though.
Another issue I had was there was no way to globally write out all the SQL that was being executed to a console/debug stream. You could to see what one query is going to do by running query.ToTraceString() but I could not find a global flag to turn this on. I have found with using other frameworks that have this feature has led me to discover lots of issues when running unit tests and seeing some of the unexpected SQL that is being generated.
Another interesting issue is source control and the EF. EF generates one big class file and one big XML file for the model. If you have a team of more than one person chances are that multiple people will be working on the model at the same time which is going to inevitably lead to a locking/merging nightmare. Having many small files reduces this problem.
The thing that really bugs me about this product is the apparent attitude of the team behind it. There are many good evolved OR/M tools out there already and it feels like they looked at none of them. The team has also apparently not taken any of the community feedback from the betas (or a very very small amount of it) and incorporated it in. My outside impression of the EF team is that they are disconnected from the real world, the community, and the competition to their framework.
The thing that stopped me from looking at EF any further was the refactoring support. I am a big big resharper user and it does not play with EF. I renamed one property of an object generated by EF and everything compiled just fine. When I ran the application and tried to save/load the entity I got the lovely error of “The Member ‘Location’ in the conceptual model type ‘Model.Permit’ is not present in the OSpace type ‘EntityFramework.Stub.Permit’”. Refactoring is a fact of development now days and for EF to fail on a simple rename like this ruled it out for me.
Designing a domain driven application gives us limitless possibilities in how we can express a business and its rules. The application and the database are not a homogenous system, they each have their own roles. A database is just a bucket we store the state of things in. The entity framework makes it feel like my application has to adapt to that bucket so therefore my business is a bucket which in turn makes my application work like a bucket and most clients don’t want a bucket application. The fact that there even is an Entity Framework Vote Of No Confidence that hundreds of developers have signed is good evidence that this product missed the mark and will continue to unless they make some massive changes. Overall I found the EF to be overly complex, frustrating, and not nearly flexible enough for me and I will avoid it at all costs on future projects.