The second D3 release is now up at: d3-0.0026.zip It’s the fruit of my labors pretty much full-time this week because it has been “App Week” on the EF team this week.
What a great time! My kids got out of school for summer break last Friday (which means I have the option of sleeping in rather than waking up early to drive the car pool), and this week I got to almost completely clear my calendar and spend time working on DPMud. App week is a time we set aside periodically to devote as much of our attention as possible to using the EF and related technologies to build applications so that we can experience some of the joys (and pain) of our valued customers. Most everyone looks forward to it, and we invariably find lots of great opportunities to improve the product.
While most other folks have been building new applications from scratch, I devoted my week to concentrated time on my long-running favorite app and just picked the next task off my to-do list and went to work. That task was to add a concurrency-token property to each of my entities and a simple test to verify that optimistic concurrency checks are working correctly. Seems pretty simple right? The model currently only has 4 entities, so how hard could it be? Can you say “working all week on this one task”? :-(
I won’t claim to be a test-first kind of developer, and the test code below is something I wrote after I had things working rather than first, but I’ll show it to you first so you can capture the goal. Then we’ll talk through the challenges I encountered and how I conquered them (in the hope that I can save you some pain). If you remember from my post about the last release, each entity currently in the model has a similar set of scalar properties but different relationships. My idea was to just add a Version property which would be marked as a concurrency token and setup to be automatically updated in the database any time any property on the entity changes so that we would get automatic concurrency checks. This property should actually have protected visibility because I don’t want to interact with it directly when using my entities—I just want the EF to use it and maintain it for me. The result would enable this test helper method:
private void VerifyConcurrency<T>(Func<T> create, Action<T> modify) where T : class{ using (var ctx = Utilities.CreateTestContext()) { var objectSet = ctx.CreateObjectSet<T>(); var obj = create(); objectSet.AddObject(obj); ctx.SaveChanges(); using (var ctx2 = Utilities.CreateTestContext()) { var key = ctx.ObjectStateManager.GetObjectStateEntry(obj).EntityKey; var obj2 = (T)ctx2.GetObjectByKey(key); modify(obj2); ctx2.SaveChanges(); } modify(obj); ctx.SaveChanges(); }}
So it was time to customize the model first process again, but before I got even that far I ran into a bug. Ahhh… The joy of AppWeek and of beta software. The issue is that if you set Concurrency Mode to Fixed on any of your entities in VS 2010 beta 1, then when you choose Generate Database Script from Model, the tool will display an error rather than generating the script. Considerable debugging and discussion with the developer who did most all of the work for model first later, we were able to track the problem down to a one line problem where model first was assuming that all property facets that could be set in the conceptual model were at least valid possibilities for the storage model, when in fact Concurrency Mode is the one property which can only be in the conceptual model and not the storage model. So the workflow activity that generates the SSDL from the CSDL was triggering an exception from the metadata system.
This bug will be fixed in beta 2, but that doesn’t help us much for D3 right now. So my final solution was to extract a small piece of the model-first workflow into a separate DLL, make a fix to the code and then modify the DbGen.xaml file which describes the workflow to call out to that DLL rather than the core version that ships with the product. The final result is part of this release, and it’s called modelfirst-bugfix.dll. If you go the misc directory under the release and run the batch file install-bugfix.cmd it will copy the DLL to a directory in your VS installation (make sure you run this from a VS command prompt where the DevEnvDir environment variable is set). Naturally this little hack is completely unsupported, but it works for me, and it might work for you too if you need to use model first with concurrency and beta 1 of EF4.
Now at least I can run model first when I have concurrency configured, but I’ve still got the problem that my properties come through as binary rather than RowVersion type in the DB. That’s where I’ll pick up the next post… Until then, happy coding.
- Danny