There are occasions where it isn’t feasible or desirable to store our entity as a single document in RavenDB. A question that just came up was how to design votes for an entity using RavenDB.
The scenario is simple, we have our entity, Question (think stack overflow), which can have Up/Down votes. It would be very easy to design the system using a single document for the entity, like so:
{ //document id: questions/123 Title: "How to handle Up/Down votes with Raven?", Content: "...", Votes: [ { Up: true, User: "users/ayende" }, { Up: false, User: "users/oren" }, ] }
As usual, the problem begins when you start to consider what happens when you want to deal with questions that may have large number of votes, or the common scenario where you just want to display the vote totals, and not pull the entire document to get that.
One option is to split things up. I guess you figured that out from the title of this blog post. The idea is to change the document structure to be:
{ //document id: questions/123 Title: "How to handle Up/Down votes with Raven?", Content: "...", } { //document id: questions/123/votes Votes: [ { Up: true, User: "users/ayende" }, { Up: false, User: "users/oren" }, ] }
Note that we have two separate documents here. Now we can load just the questions, or the questions and the votes. We still have a problem with getting the totals without loading potentially thousands of votes. It is pretty easy to solve this, however, using the following index:
from voteDoc in docs.VoteDocs from vote in voteDoc.Votes group vote by vote.Up into g select new { Up = g.Key, Count = g.Count() }
Now we can query the index directly, to get the aggregated results:
session.LuceneQuery<VoteTotals>("Questions/VoteTotals") .SelectFields("__document_id", "Up", "Count") .ToList();
And if we want to get the votes themselves, they are easily available as well.
I got a lot of interesting answers for the riddle, and here is my solution:
private static int sequentialUuidCounter; public static Guid CreateSequentialUuid() { var ticksAsBytes = BitConverter.GetBytes(DateTime.Now.Ticks); Array.Reverse(ticksAsBytes); var increment = Interlocked.Increment(ref sequentialUuidCounter); var currentAsBytes = BitConverter.GetBytes(increment); Array.Reverse(currentAsBytes); var bytes = new byte[16]; Array.Copy(ticksAsBytes, 0, bytes, 0, ticksAsBytes.Length); Array.Copy(currentAsBytes, 0, bytes, 12, currentAsBytes.Length); return bytes.TransfromToGuidWithProperSorting(); }
Basically, we use the current system ticks as the 1 – 8 bytes, and a counter incremented atomically on the 12 – 16 bytes. This ensures that even concurrent calls on the same tick will have a different value.
Note that this code explicitly allows the same guid on multiple machines. You can fix that by adding the MAC address as 9 – 12 bytes, which will make this globally unique, but this isn’t something that I actually need.
Additional challenge, why am I reversing the bytes?
The following features apply to NHProf, EFProf, L2SProf.
In general, it is strong discouraged to data bind directly to an IQueryable. Mostly, that is because data binding may actually iterate over the IQueryable several times, resulting in multiple queries being generated from something that can be done purely in memory. Worse, it is actually pretty common for data binding to result in lazy loading, and lazy loading from data binding almost always result in SELECT N+1. The profiler can now detect and warn you about such mistakes preemptively. More than that, the profiler can also now detect queries that are being generated from the views in an ASP.Net MVC application, another bad practice that I don’t like.
You can find more information about each warnings here:
WPF detection:
WinForms detections:
Web applications:
One of the reasons that people tell you to avoid Silverlight is the SEO cost. Since Justin’s blog is written in Silverlight, I thought that I might take it for a spin in Lynx, the text only browser, and see what Google sees.
My blog in Lynx:
Justin’s blog is Lynx. His actually looks better than mine in Lynx :-).
I recently got a bug report about an issue with EF Prof, apparently the application statistics would record the context being opened, but it wouldn’t show them being closed. The customer was rightfully worried about that, and wanted to know if this is a bug in his code or in EF Prof.
Not closing connections is a pretty bad idea, obviously, because you are going to hold a lot more server resources than you need.
But we couldn’t figure out what the problem was. On my end, I could see that EF Prof was recording the context close properly, but nearly the same code on the customer showed the problem. Note the word nearly. I asked for a repro of the issue, and once I had it, it took mere minutes to confirm that the problem exists.
Now was the time to find out why. The customer code was:
using(var context = new MyContext(new EntityConnection("name=MyConStr")) { // do stuff }
Now, what EF Prof tells you is a data context open & close are actually more accurately connection open & close. After some extensive study, I verified that it wasn’t my code to blame, there was a leaking connection here.
Checking a bit further, it became clear. We passed an existing connection to the context. When we dispose the context, the context asks: “Am I the owner of this connection?” And since the answer is no, it will not dispose it. It makes sense, you might want to use that connection for your own purposes, and it is pretty rude of the context to close a connection that it doesn’t own.
How can we resolve this? By giving the context the information to open the connection, but not the connection itself:
using(var context = new MyContext("name=MyConStr") { // do stuff }
This code will instruct the context to open its own connection, which it will know that it owns, so it can safely dispose it when it is disposed.
Look Ma, no leaks!
This is a rather special request, I’ll admit. For reasons of my own, I need to find the method(s) called to actually performed data binding in WPF & WinForms.
WPF is actually quite simple:
WinForms, not so much. I resorted to creating a strongly typed data source and concating my extension there.
The answers are, by the way:
WPF:
- at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
- at MS.Internal.Data.DataBindEngine.Run(Object arg)
WinForms:
- at System.Windows.Forms.CurrencyManager.SetDataSource(Object dataSource)
- at System.Windows.Forms.BindingContext.EnsureListManager(Object dataSource, String dataMember)
This is a rather special request, I’ll admit. For reasons of my own, I need to find the method(s) called to actually performed data binding in WPF & WinForms.
I have an elegant solution, which is too large to include in this blog post, but I’ll say that it doesn’t involves reflector at all.
Can you figure it out?
I just finished implementing a very cool feature for RavenDB, the Index Replication bundle allows you to replicate an index to a relational database.
What does this mean? Well, consider the following document:
var q = new Question { Title = "How to replicate to SQL Server?", Votes = new[] { new Vote{ Up = true, Comment = "Good!"}, new Vote{ Up = false, Comment = "Nah!"}, new Vote{ Up = true, Comment = "Nice..."}, } };
And this index:
from q in docs.Questions select new { Title = q.Title, VoteCount = q.Votes.Count }
With the aid of the Index Replication bundle, that index will be replicated to a relational database, giving us:
You can find full documentation for this feature here and the bundle itself is part of RavenDB’s unstable as of build 159.
I got the following bug report about NH Prof:
When renaming a session, the "enter" key seems to invoke the "Cancel" rather than the "Rename Session" button - this is slightly annoying (and unexpected) behavior.
But that is impossible, here is the XAML for this:
And as it turned out, the code is correct, and the explanation for the error is wrong, but the behavior exists.
The actual problem turned out to be that if you hit enter while the focus is on the text box, the RenameSession method will be called, but the bound value will not be modified, since the default binding mode for text boxes is on focus lost. We can fix this using:
Although this is logical, considering how WPF works, I still find it surprising, I would expect this to be a common scenario that would be handled OOTB.