// GET: Captain public ActionResult Index() { Dictionary <int, int> votes = new Dictionary <int, int>(); //Perform a multi shard query to tally all the votes // Get the shards to connect to var shards = _shardMap.GetShards(); // Create the multi-shard connection using (var conn = new MultiShardConnection(shards, Util.SqlHelper.GetCredentialsConnectionString())) { // Create a simple command using (MultiShardCommand cmd = conn.CreateCommand()) { // Because this query is grouped by CustomerID, which is sharded, // we will not get duplicate rows. cmd.CommandText = @"SELECT Captain, COUNT(*) AS Votes FROM [dbo].[Votes] GROUP BY [Captain]"; // Allow for partial results in case some shards do not respond in time cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults; // Allow the entire command to take up to 30 seconds cmd.CommandTimeout = 30; // Execute the command. // We do not need to specify retry logic because MultiShardDataReader will internally retry until the CommandTimeout expires. using (MultiShardDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { votes.Add(reader.GetInt32(0), reader.GetInt32(1)); } } } } var vm = new ViewModels.Captain.IndexViewModel(); foreach (var captain in _captainContext.Captains) { int voteCount = 0; votes.TryGetValue(captain.ID, out voteCount); vm.Captains.Add(new ViewModels.Captain.IndexViewModelCaptain() { ID = captain.ID, Name = captain.Name, Votes = voteCount }); } return(View(vm)); }
public void TestDataReaderReadException() { // Setup two data readers from shards var mockReader1 = new MockSqlDataReader("Reader1"); var mockReader2 = new MockSqlDataReader("Reader2"); bool movedOnToNextReader = false; int invokeCount = 1; Func <MockSqlDataReader, Task <bool> > ExecuteOnReadAsync = (r) => { return(Task.Run <bool>(() => { // First reader throws an exception when Read if (r.Name == "Reader1") { if (invokeCount == 2) { throw new InvalidOperationException(); } } else { movedOnToNextReader = true; } return true; })); }; Action <MockSqlDataReader> ExecuteOnGetColumn = (r) => { if (r.Name == "Reader1") { throw new InvalidOperationException(); } }; mockReader1.ExecuteOnReadAsync = ExecuteOnReadAsync; mockReader1.ExecuteOnGetColumn = ExecuteOnGetColumn; mockReader2.ExecuteOnReadAsync = ExecuteOnReadAsync; var labeledDataReaders = new LabeledDbDataReader[2]; labeledDataReaders[0] = new LabeledDbDataReader(mockReader1, new ShardLocation("test", "Shard1"), new MockSqlCommand() { Connection = new MockSqlConnection("", () => { }) }); labeledDataReaders[1] = new LabeledDbDataReader(mockReader2, new ShardLocation("test", "Shard2"), new MockSqlCommand() { Connection = new MockSqlConnection("", () => { }) }); // Create the MultiShardDataReader var mockMultiShardCmd = MultiShardCommand.Create(null, "test"); var multiShardDataReader = new MultiShardDataReader(mockMultiShardCmd, labeledDataReaders, MultiShardExecutionPolicy.PartialResults, false); // Validate that if an exception is thrown when reading a column, // it is propagated back to the user try { multiShardDataReader.Read(); invokeCount++; multiShardDataReader.GetInt32(0); } catch (Exception ex) { Assert.IsTrue(ex is InvalidOperationException, "Expected InvalidOperationException!"); } // Validate that we didn't automatically move on to the next reader when we // hit an exception whilst reading the column and that // an exception from a second Read() call is stored and the reader is closed multiShardDataReader.Read(); Assert.AreEqual(multiShardDataReader.MultiShardExceptions.Count, 1, "Expected exception to be recorded"); Assert.IsTrue(mockReader1.IsClosed, "Expected reader to be closed!"); // Validate we immediately moved on to the next reader multiShardDataReader.Read(); Assert.IsTrue(movedOnToNextReader, "Should've moved on to next reader"); }