Lots have been said about Entity Framework, in past mostly bad things. Lately I hear more and more voices speaking in advantage of this library. It is being said that it has reached maturity point and is actually usable now. Of course it was usable earlier, but it had its quirks. Unfortunately some are still there. I have recently found one that I couldn’t really believe is true. I had(also severe) problems with EF before, but this one is absolutely no-go for me. If exception message below reads familiar, then most probably you are experiencing it too.
Schema specified is not valid. Errors:
The mapping of CLR type to EDM type is ambiguous because multiple CLR types match the EDM type ‘<<entity name>>’. Previously found CLR type ‘<<namespace1.entity name>>’, newly found CLR type ‘<<namespace2.entity name>>’.
So what is going on here?
Entity Framework EDMX files are getting processed during compilation and in some form of multiple files end up in output directory of your application. Then, at runtime, EF library picks up these files to use contained there informations about mapping between your classes and database. As long as you have only one of these EDMX files you are on the safe side when it comest to this issue. As soon as you get more of them you are exposed. These data models definitions files might come not only from projects in your solution but also from for example NuGet packages. If in at least two of these you have defined classes, which are named exactly the same you will get mapping error as described above, regardless of different namespaces in which classes are defined. Unfortunately you will first time get to know about this at runtime. Aside from Google search and Stack Overflow this page provides lots of details.
Is it really that bad?
Oh, it is bad. Really. Check out the following scenario:
Ron is developing invoicing application, part of which is archiving files. Archiver module is developed independently by Judy. Both developers have met and defined what functionality of archiving module will be necessary – an interface. According tho the dependency inversion principle Ron is not relaying on anything else then this interface. Except code review he does not care about how Judy will implement her part as long as she can successfully satisfy their contract. Ron have event written some tests to check if Judy’s code does that. They both decide to use EF model-first, because it has nice tools build-in in Visual Studio.
Judy delivers her component by publishing NuGet package to company’s internal feed. It all goes fine, programmers integrate often and run some system tests to make themselves sure that system works fine. But then, one time lots of tests fail with the message presented at the top of this post. Ron examines his changes and can’t see what could have caused the problem. So he speaks with Judy. It turns out that in newest version of archiving module Judy added an entity called “Invoice“. Ron already has entity with this name. They decide that it will be easier to rename entity in Judy’s code to “InvoiceDocument“, seems to be least work from all considered possibilities. It will break their ubiquitous language, but sprint review is approaching, so they want to make stuff work. They of course add this to their technical debt log, so that they can resolve it in the future(never I tell you).
After updating package to newly published version Ron still experiences this exception.. just with a different entity name, this time it’s “Document”. Why? It turned out that Judy uses another NuGet package developed by Jake, who is no longer working in this company. Judy needs it, because company is pretty strict about the naming of files stored in archive, and this component provides exactly this functionality – constructing names. Alas! There is “Document” entity defined in this package. So what they’re gonna do now? Ron decides to change his model so that it doesn’t contain “Document” entity anymore, he will rename it to “InvoiceDocument“.. ahh, no this name is taken, so to “PaymentDocument“. This seems easier to do it in a project, that he knows well, than in some long-forgotten library that he have never seen. They repeat this dance as long as necessary (usually not that many times). They finally stabilized it, all works fine, sprint review goes really well (till next time).
Three weeks after that Alex, who develops reporting application, comes into the room and talks with Judy. It turned out that now he experiences same problem. He updated archiver package to the newest version, but in his project entity “InvoiceDocument” exists since long time. And so the story goes…
What have just happen here? For me it seems like because of bug in EF all authors of applications that (directly or indirectly) use certain package(s) are relying on implementation detail of this package! It is not due to choice that any of these authors have made explicitly. This choice was unconsciously made by picking EF model-first as a tool to be used in their project. But wait, it is even worst, because they didn’t make this unconscious choice themselves. It was made collectively, over time, over different packages. Furthermore changes made to alleviate the original problem have led to problem recurring in different systems.
It seem that probability of this bug getting in your way has positive correlation with reuse that you do in your company and common domain language. This actually means that the better you work the more you are exposed to it. And let me just say that this scenario is not fully made up.
Also this is bad on completely different level. How long should bug like this live? This one is known issue since beginning of the EF. Come on!
Alternatives and workarounds
Obvious alternative is to use different ORM (yes, I like NH) or use overall different approach to data access. I am not fan of plain SQL, but I worked with such approach and know that it can work quite OK(ish).
If you are forced to use EF for example by stupid company rules or some guy who lost contact with reality after being called architect you can go with code-first approach. This error exists only in model-first approach. If you will switch to code-first you will (finally!) also make your connection string free from this EF characteristic clutter, that always makes you scroll right to see actual connection string even on HD+ displays.
You can either redo your data models manually or use tool to help you. Use scroll on this thread to get more infos about tools.
Even if you decide to do it manually to save yourself some work you can most probably just use classes definitions generated by t4 templates. They have been generated automatically for you when you have been still using EDMX, they should reside on your hard drive. Just copy them to your new DataModels (or whatever it is called at your place) project. This does not mean no work, you will still have to do some stuff. Especially if you have put some work in mapping, for example to mask shortcoming of your database(like inconsistent naming). All this mapping information will have to be re-enterd.