I will never stop being amazed by the wonders of OSS.
Think about it: a lot of people have a problem, some of the guys with the problem have the knowledge and the drive to solve it and they even have the guts to let everyone see and scrutinize their code so that others with the same or similar problem can take advantage of their efforts.
Furthermore, once the solution is on the wild, random people have their saying asking for tweaks or proposing new challenges altogether and some of them take it one notch further and solve their own and someone else’s troubles.
Who could have wondered?
That is exactly what happened with NMoneys. A user wanted to store monetary quantities in a relational database using Entity Framework (EF) and it turns out one can’t do that when the type to be persisted is a value type (so much for the complex types promises of scalar “values” using non-scalar properties).
He even took the extra step of suggesting a solution for the problem.
EF received quite a beating when it first launched. And not without grounds. The “old” MS launched a subpar product (compared to some other ORMs at the time) missing the chance to give a boost to an Open Sourced, superior one and selling the craziness of “is not an ORM, there will be entities for everything” (we know where we are now on that) and putting Visual Studio designer lipstick on a ORM-pig.
Those days are long gone, giving up on being more than an ORM to become a decent-enough ORM. EF got code-first development style, migrations and some features that has made it usable. Yes, there are better solutions. And yes, one should consider whether to use an ORM at all (or go relational for that matter); but, all things considered, if someone (a user of NMoneys) uses it and takes all the steps to have a feature… Does it matter that the product is not of my liking?
However, regardless of my personal opinions, the fact is that I am not an EF user despite having an old and dusty (and barely opened) Programming Entity Framework book on my desk because I got it from the author herself.
So I took advantage of the time my employer provided me to do something I would normally do on my scarce spare time during working hours and went onto learn some EF and how one could use it in tests projects.
Testing with EF
When databases enter the picture one can start forgetting about pure, isolated tests and needs to start thinking about integration tests that can be the faster one can achieve.
Embedding the Db
Unfortunately, I could not find an in-memory database that could work with EF.
Next one in line would be an embedded database, which removes the need of installers and/or running services in order for tests to run. For that purpose I found the package EntityFramework.SqlServerCompact to be pretty easy to get started with.
I explored the need to manage database files using
SqlCeEngine. But it is not even needed, as EF code-first would take care of creating the database when it does not exist. So in order to be self-contained, test fixtures only need to take care of cleaning out database files.
Next step is to have a
DbContext implementation that makes use of that file. You can check its source here.
No Config is Better Config
Next step is breaking away from configuration. In tests, I prefer to not rely on app configuration, but the NuGet package configures providers and connection factories using configuration. After some googling I found out that one can drop an implementation of
DbConfiguration and the framework will pick it up and apply it for all contexts. Sweet! That is how you configure SQL Server Compact using code:
The NMoneys Bits
So, we have a context we can use in our tests and the tests will clean the “data mess”, isn’t this a NMoneys post? Was it only click-bait ?
Well, we need a class that can store
Money information. How about
MonetaryQuantity for a name? If fact, it is a pure POCO reference type that does not depend on EF at all.
Of course there are some design decisions that smell EF:
- like the fact that instead of storing a
CurrencyIsoCodea three-letter string is used, due to the fact that in 2016 EF (version 6 at least) does not allow storing textual representations of enumerations without jumping though hoops. Really Microsoft, really?
- or the existence of a default private constructor, but I cannot blame EF for that as it is a very common requirement
The bits that make this POCO object persistable are inside the
MonetaryQuantityCanonicalConfigurator that will turn this POCO into a propert complex type via its
.Configure() methods that map the properties to suitable columns in a db-agnostic fashion and that should be called from your context’s .OnModelCreating() initialization method.
Yes, there are missing bits... But that is what future releases are for, ain't it?
The delivery method is, as with all 3rd party serialization, code is delivered as a NuGet package containing source code so that you can customize to your needs. One honorable difference is the fact that in this case, the package does depend on EF’s package, as I know things are going to change substantially with the advent of EF7 and I wanted to see whether that is indeed a problem or not.