Hands-On MVVM video
Friday, November 5th, 2010Many thanks to Shawn Weisfeld for recording my Hands-On MVVM session at the Forth Worth .NET User’s Group.
Archive for the ‘Patterns’ CategoryHands-On MVVM videoFriday, November 5th, 2010Many thanks to Shawn Weisfeld for recording my Hands-On MVVM session at the Forth Worth .NET User’s Group. Hands-on MVVM 4b: Communicate through the data modelFriday, May 14th, 2010I presented this material at Dallas XAML on May 4, 2010. Please download the demo code and follow along. This post takes us the rest of the way the project called “Step4”. When we left the project in part 4, we had injected a layer between the model and the view. In the process, we broke updates. Now let’s fix them. Add INotifyPropertyChanged to the view model
Neither WPF nor Silverlight need you to fire PropertyChanged for a property that the view itself is changing. The view already knows that it has changed. It’s the one that changed it! The updates that failed are all related to dependent properties. DisplayAs depends upon first name, last name, and email. Title depends upon DisplayAs. We moved both of these properties into the view model. So the view model needs to know when these properties change. Possible solution: interception public string FirstName { get { return _person.FirstName; } set { _person.FirstName = value; FirePropertyChanged("Title"); } } public string LastName { get { return _person.LastName; } set { _person.LastName = value; FirePropertyChanged("Title"); } } public string Email { get { return _person.Email; } set { _person.Email = value; FirePropertyChanged("Title"); } } public string Phone { get { return _person.Phone; } set { _person.Phone = value; } } public DisplayStrategyViewModel DisplayAs { get { return new DisplayStrategyViewModel(_person, _person.DisplayAs); } set { _person.DisplayAs = value.DisplayStrategy; FirePropertyChanged("Title"); } } When the user changes any of the properties that Title depends upon, the view model fires PropertyChanged for the Title. Title does not depend upon Phone, so that one doesn’t fire. The view model is keeping track of dependencies. But what about the DisplayStrategyViewModel? It doesn’t intercept the properties that it depends upon. It needs to be notified when FirstName, LastName, or Email is changed. That means that PersonViewModel would have to send these notifications to DisplayStrategyViewModel. That’s too much coupling between the two. Let’s find a different solution. Better solution: indirect notification The view models already have something in common. They both know about the Person data model. Let’s allow them to communicate with each other through the data model. When the PersonDataModel changes one of the properties on the Person object, the DisplayStrategyViewModel should hear about it. It needs to know about those property changes. We have, conveniently enough, a mechanism for listening to property changed events. Although INotifyPropertyChanged is intended for data binding, you can use it for your own internal notification as well. Person already implements INotifyPropertyChanged. But it used to fire property changed events for dependent properties. Now we want to know about changes to the properties themselves. Let’s add those notifications. public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string FirstName { get { return _firstName; } set { _firstName = value; FirePropertyChanged("FirstName"); } } public string LastName { get { return _lastName; } set { _lastName = value; FirePropertyChanged("LastName"); } } public string Email { get { return _email; } set { _email = value; FirePropertyChanged("Email"); } } public string Phone { get { return _phone; } set { _phone = value; FirePropertyChanged("Phone"); } } } Person no longer keeps track of dependent properties. That’s the view model’s job. Now it’s firing PropertyChanged events so that the view models can collaborate with each other. To close the loop, DisplayStrategyViewModel needs to listen. public class DisplayStrategyViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public DisplayStrategyViewModel( Person person, DisplayStrategy displayStrategy) { _person = person; _displayStrategy = displayStrategy; _person.PropertyChanged += PersonPropertyChanged; } private void PersonPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "FirstName" || e.PropertyName == "LastName" || e.PropertyName == "Email") FirePropertyChanged("Display"); } } Now when the PersonViewModel changes one of the properties that DisplayStrategyViewModel depends upon, it can notify the view. Best solution: automatic dependency management Wouldn’t it be better if you didn’t have to write all of that dependency management code in the view model? You don’t, if you use Update Controls. But this isn’t an Update Controls presentation, so back to doing it manually. Finish it out To finish the transition from the interception solution to the notification solution, we remove the interceptors from the PersonViewModel. Instead, that view model also listens to changes. public class PersonViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private Person _person; public PersonViewModel(Person person) { _person = person; _person.PropertyChanged += PersonPropertyChanged; } void PersonPropertyChanged(object sender, PropertyChangedEventArgs e) { FirePropertyChanged("Title"); } } Now all of the view models listen to changes in the data model. If anything changes the data model, the view model will notify the view of changes to dependent properties. It’s like a publish-subscribe mechanism, but we’re using the data model itself. The data model has become the conduit for messages. Next time, we’ll upgrade our application to manage a collection of people. In the process, we will dispel some of the myths about ObservableCollection. Convention-based view model registrationSunday, May 9th, 2010When you create a ListBox or ItemsControl, you usually specify an ItemTemplate to render each of the items. You can do so directly in the ItemsControl itself. <ListBox ItemsSource="{Binding Projects}" SelectedItem="{Binding SelectedProject}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> Or you can identify a resource by name. <UserControl.Resources> <DataTemplate x:Key="ProjectItemTemplate"> <TextBlock Text="{Binding Name}"/> </DataTemplate> </UserControl.Resources> <ListBox ItemsSource="{Binding Projects}" SelectedItem="{Binding SelectedProject}" ItemTemplate="{StaticResource ProjectItemTemplate}"/> Either of these methods causes every item to be rendered in the same way. But what if different kinds of items are represented with different views? If you want each item to be rendered according to its type, you can add all of the data templates to the resource dictionary. The list will select the data template based on the item type. <UserControl.Resources> <DataTemplate DataType="{x:Type projects:SoftwareProject}"> <StackPanel> <TextBlock Text="{Binding Name}"/> <TextBlock Text="{Binding LinesOfCode}"/> </StackPanel> </DataTemplate> <DataTemplate DataType="{x:Type projects:HardwareProject}"> <StackPanel> <TextBlock Text="{Binding Name}"/> <TextBlock Text="{Binding ServerCount}"/> </StackPanel> </DataTemplate> </UserControl.Resources> <ListBox ItemsSource="{Binding Projects}" SelectedItem="{Binding SelectedProject}"/> Convention over configuration You can explicitly add data templates to a resource dictionary if you have only a few closely related types to choose from. But explicit configuration becomes tedious if this set of types changes frequently, if there are many of them, or if they are located in different namespaces. In some cases, it is easier to adopt a convention-based approach. I started the WPF LOB project on Codeplex to experiment with patterns for line-of-business applications in WPF. One of those patterns is switching among views within the same window. The project defines a base class for view models that represent panes within the window. It uses convention over configuration to associate those view models with their views. The main form looks for all classes that inherit from Pane and end with the words “ViewModel”. By convention, the view model will be located in a namespace called “ViewModel”. The associated view will be a user control located in a namespace called “View”, and ending with the word “View”. The main form applies that convention to locate the view, and adds a data template to the resource dictionary. public MainWindow() { InitializeComponent(); RegisterAllPanes(); } private void RegisterAllPanes() { // Find all pane view model types in the assembly. Assembly assembly = Assembly.GetExecutingAssembly(); foreach (Type viewModelType in assembly.GetTypes()) { if (typeof(Pane).IsAssignableFrom(viewModelType) && viewModelType.Name.EndsWith("ViewModel")) { string viewTypeName = viewModelType.FullName.Replace("ViewModel", "View"); Type viewType = assembly.GetType(viewTypeName); if (viewType != null) RegisterDataTemplate(viewModelType, viewType); } } } private void RegisterDataTemplate(Type viewModelType, Type viewType) { DataTemplate dataTemplate = new DataTemplate(viewModelType) { VisualTree = new FrameworkElementFactory(viewType) }; Resources.Add(dataTemplate.DataTemplateKey, dataTemplate); } Caliburn Rob Eisenberg created an MVVM framework called Calliburn that relies heavily on convention over configuration. His framework goes so far as to data bind controls to properties based on convention, rather than configuring each using the “{Binding}” markup extension. Watch his presentation from Mix10. If you would like to develop applications within the realm of his opinion, I recommend investing the time in learning Caliburn. But even if you don’t, you can still use simple techniques like the one above to take advantage of convention over configuration when it makes the most sense. Hands-on MVVM 4: the View Model layerFriday, May 7th, 2010I presented this material at Dallas XAML on May 4, 2010. Please download the demo code and follow along. This post takes us half way the project called “Step4”. The next one will take us the rest of the way, but then the numbers will be out of sync. In part 3, we added a “Display As” feature to the system. In doing so, the data model started getting messy. This time, we’ll pull those view-specific features out of the data model. The data model has a job to do. It evaluates domain logic. That’s already enough for a single class. We don’t want to further burden it with managing a view. Robert C. Martin tells us of the Single Responsibility Principle. A class should have only one reason to change. If you’re changing the data model, it’s because you are modifying the domain. You shouldn’t also change it when modifying the behavior of a view. So let’s move that behavior out of the data model. The place it goes is the View Model. We data bind to the view model rather than to the data model. View-specific properties public class PersonViewModel { private Person _person; public PersonViewModel(Person person) { _person = person; } public string Title { get { return "Person - " + _person.DisplayUsingStrategy(_person.DisplayAs); } } } The Person View Model takes a reference to a Person. It uses the Person to provide the desired behavior. Pass-through properties The view displays text boxes where the user can edit the properties of a person directly. Since the view is no longer bound directly to the data model, we have to pass these properties through the view model. public class PersonViewModel { private Person _person; public PersonViewModel(Person person) { _person = person; } public string FirstName { get { return _person.FirstName; } set { _person.FirstName = value; } } public string LastName { get { return _person.LastName; } set { _person.LastName = value; } } public string Email { get { return _person.Email; } set { _person.Email = value; } } public string Phone { get { return _person.Phone; } set { _person.Phone = value; } } public string Title { get { return "Person - " + _person.DisplayUsingStrategy(_person.DisplayAs); } } } No data is stored in the view model itself. It all passes through to the data model. One view model per DataContext The “Display As” combo box has an ItemsSource that is data bound to a collection. Each item in this collection is the DataContext of one combo box item. Before it was a string. Now we’ll make it a view model of its own. public class DisplayStrategyViewModel { private Person _person; private DisplayStrategy _displayStrategy; public DisplayStrategyViewModel(Person person, DisplayStrategy displayStrategy) { _person = person; _displayStrategy = displayStrategy; } public string Display { get { return _person.DisplayUsingStrategy(_displayStrategy); } } } Again, this view model passes its behavior through to the Person object. But now it displays that person according to a given display strategy. We use a DataTemplate to show that property in the combo box. <ComboBox ItemsSource="{Binding DisplayAsOptions}" SelectedItem="{Binding DisplayAs}"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Display}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> And now we need to generate these view models. Project through a factory The simplest way to generate a collection of view models is to use linq to project a collection of data objects through a view model constructor. In this case, we are listing all of the display options, so we project the values of the DisplayStrategy enumeration. We add this property to the Person View Model. public IEnumerable<DisplayStrategyViewModel> DisplayAsOptions { get { return Enum.GetValues(typeof(DisplayStrategy)) .OfType<DisplayStrategy>() .Select(displayStrategy => new DisplayStrategyViewModel(_person, displayStrategy)); } } From the list of DisplayStrategy values, we produce a list of Display Strategy View Models that render the person using different options. ItemsSource/SelectedItem duality Finally, the user needs to select one of the display strategies from the combo box. The SelectedItem property provides this behavior. It is the dual of the ItemsSource property: its type must be the same as the IEnumerable generic parameter. public DisplayStrategyViewModel DisplayAs { get { return new DisplayStrategyViewModel(_person, _person.DisplayAs); } set { _person.DisplayAs = value.DisplayStrategy; } } This property wraps the DisplayAs selection in a view model so that it agrees with the type of the list. Equals and GetHashCode If you were to run the code now, you would see that the window comes up initially blank. But when you select a “Display As” setting, it appears correctly. The problem is that the view cannot find the SelectedItem in the ItemsSource collection. For each property, we created a new Display Strategy View Model. These are two different instances of similar objects. To tell the view that they are indeed the same, we need to implement Equals and GetHashCode in DisplayStrategyViewModel. public override bool Equals(object obj) { if (obj == this) return true; DisplayStrategyViewModel that = obj as DisplayStrategyViewModel; if (that == null) return false; return _displayStrategy == that._displayStrategy; } public override int GetHashCode() { return _displayStrategy.GetHashCode(); } Now the view recognizes that they are the same, so the window appears correctly. You must always implement Equals and GetHashCode when you create an ItemsSource/SelectedItem dual. We have successfully moved the view-specific behavior out of the data model and into a view model. We pass all of the properties that are data-bound to the view through to the data model. By projecting related objects through a constructor, we can keep a view model layer in between the view and the data model at all times. The application works now, but there are a few places that no longer update. That’s because we didn’t implement INotifyPropertyChanged on the view model to tell the view about dependent properties. In part 4, we’ll add INotifyPropertyChanged to get that behavior back. Hands-on MVVM 3: ItemsSource and SelectedItemWednesday, May 5th, 2010
In part 2, we saw why we need to fire PropertyChanged events. It’s not for the benefit of the properties that the view is changing directly. It’s for the dependent properties. Display strategy The chosen display strategy is stored with the person. The user can choose to display one person using their formal name (last-first), and another using their informal name (first-last). It is not a global setting. The user selects a display strategy from a combo box. We add this to the person view. <ComboBox Grid.Row="4" Grid.Column="1" x:Name="displayAs" ItemsSource="{Binding DisplayAsOptions}" SelectedItem="{Binding DisplayAs}"/> This combo box needs to show a list of options. We’ll generate these options by applying different display strategies to the person. public IEnumerable<string> DisplayAsOptions { get { return Enum.GetValues(typeof(DisplayStrategy)) .OfType<DisplayStrategy>() .Select(displayStrategy => DisplayUsingStrategy(displayStrategy)); } } public string DisplayUsingStrategy(DisplayStrategy displayStrategy) { if (displayStrategy == DisplayStrategy.LastFirst) return string.Format("{0}, {1}", _lastName, _firstName); else if (displayStrategy == DisplayStrategy.FirstLast) return string.Format("{0} {1}", _firstName, _lastName); else return _email; } The DisplayAsOptions property gets all values of the DisplayStrategy enumeration and projects that set through the DisplayUsingStrategy method. The DisplayUsingStrategy method formats the person for the given strategy. The result is a collection of strings. When the user selects one of those strings, they will set the DisplayAs property. Since DisplayAsOptions is an IEnumerable<string>, DisplayAs has to be a string. public string DisplayAs { get { return DisplayUsingStrategy(_displayAs); } set { _displayAs = (DisplayStrategy)DisplayAsOptions .ToList() .FindIndex(option => option == value); } } The DisplayAs getter just applies the current display strategy for the person. The setter, however, has to find the selected string in the list of options. The index of this string corresponds to the ordinal value of the enumeration that generated it. The important thing here is the duality of the DisplayAsOptions and DisplayAs properties. DisplayAsOptions has type IEnumerable<string>. DisplayAs has type string. These types must agree, because one is data bound to ItemsSource and the other to SelectedItem. Update the title Now that the user can select the display strategy for the person, we should use that display strategy in the title of the window. We make the necessary change to the Title property. public string Title { get { return "Person - " + DisplayUsingStrategy(_displayAs); } } When we run the app, it doesn’t look like it’s working. When we change the display strategy, the title doesn’t update. Did we forget to compile? No. We just forgot to tell XAML that the title depends upon DisplayAs. public string DisplayAs { get { return DisplayUsingStrategy(_displayAs); } set { _displayAs = (DisplayStrategy)DisplayAsOptions .ToList() .FindIndex(option => option == value); FirePropertyChanged("Title"); } } Now the title updates when we change the display strategy. Messy model Take a step back and look at the model that we’ve created. The Person class has the following properties.
How many of these are actually the responsibility of the model? How many are just there to satisfy the view? As we’ve added features to the application, we’ve allowed the view’s concerns to creep into the data model. If we continue in this vein, the data model will get very messy. In part 4, we’ll pull the view’s concerns out of the data model. That’s the first time in this series that we’ll really see the MVVM pattern. Hands-on MVVM 2: Dependent propertiesTuesday, May 4th, 2010I will be presenting this material at Dallas XAML tonight (May 4, 2010). If you are in the area, please come by. If not, just download the demo code and follow along. In part 1 we created a model and a view. Now we start adding features and seeing how our code changes. Window title <Window x:Class="Step2.PersonWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:view="clr-namespace:Step2.View" Title="{Binding Title}" Height="300" Width="468"> <view:PersonUserControl/> </Window> Bound property The data context that we set was the Person model object. So we have to add this Title property to the Person. public class Person { private string _firstName; private string _lastName; private string _email; private string _phone; public string FirstName { get { return _firstName; } set { _firstName = value; } } public string LastName { get { return _lastName; } set { _lastName = value; } } public string Email { get { return _email; } set { _email = value; } } public string Phone { get { return _phone; } set { _phone = value; } } public string Title { get { return string.Format("Person - {0}, {1}", _lastName, _firstName); } } } Run the program and you’ll see that the title properly displays the person’s name. It looks like everything is working. But change the name and see what happens. The title doesn’t update when the name changes. That’s because the view doesn’t know that the title depends upon the name. Unless you have a system that automatically discovers dependencies (not discussed in this series), you have to notify the view. As you can see, INotifyPropertyChanged is not strictly necessary for data binding to work. The view worked just fine up until now. The properties were not notifying the view when they themselves were changing. That’s because it was the view that was changing them. The view already knows. You only really need INotifyPropertyChanged to notify the view when:
Dependent property In this case, the Title property depends upon the FirstName and LastName properties. So we notify the view that Title has changed when one of those properties change. public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _firstName; private string _lastName; private string _email; private string _phone; public string FirstName { get { return _firstName; } set { _firstName = value; FirePropertyChanged("Title"); } } public string LastName { get { return _lastName; } set { _lastName = value; FirePropertyChanged("Title"); } } public string Email { get { return _email; } set { _email = value; } } public string Phone { get { return _phone; } set { _phone = value; } } public string Title { get { return string.Format("Person - {0}, {1}", _lastName, _firstName); } } private void FirePropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } And now the title updates when you change the name. We are starting to see the need for a view model. The Title property has nothing to do with our data model. But we’ll let that slide for now. Today we saw what problem INotifyPropertyChanged solves, and we wrote the simplest thing that works. This is not the best thing, nor is it the right thing. We are watching the code evolve to see why we need MVVM. Next time we will add another feature to the system and see how the code responds to another change. Stay tuned. Hands-on MVVM 1: Model and ViewMonday, May 3rd, 2010I will be presenting this material at Dallas XAML tomorrow (May 4, 2010). If you are in the area, please come by. If not, just download the demo code and follow along. Microsoft has finally nailed data binding in WPF and Silverlight. It has long been ridiculed as a demo-only feature. But now it is useful in real application development. As people apply data binding to real applications, patterns have emerged. One of the most prevalent is Model-View-ViewModel. In truth, MVVM is not just one pattern. It is a collection if interrelated patterns. Each person has a different idea of what MVVM actually looks like. This is my opinion. The goal of this series is to understand why it is good to follow these patterns. We are going to start with direct data binding. We won’t add any code until we need it. When we find that things don’t work, we’ll add code to make them work. When things start to get messy, we will refactor to clean them up. The model public class Person { private string _firstName; private string _lastName; private string _email; private string _phone; public string FirstName { get { return _firstName; } set { _firstName = value; } } public string LastName { get { return _lastName; } set { _lastName = value; } } public string Email { get { return _email; } set { _email = value; } } public string Phone { get { return _phone; } set { _phone = value; } } } Notice that this class does not implement INotifyPropertyChanged. We are starting simple so we know why we need that code. The view We’ll data bind our view directly to our model. Data binding works against properties. The Person user control defines one text box for each Person property. <UserControl x:Class="Step1.View.PersonUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="#FF353535"> <Grid Margin="5"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Target="{Binding ElementName=firstName}" Content="_First Name:"/> <Label Grid.Row="1" Target="{Binding ElementName=lastName}" Content="_Last Name:"/> <Label Grid.Row="2" Target="{Binding ElementName=email}" Content="_Email:"/> <Label Grid.Row="3" Target="{Binding ElementName=phone}" Content="_Phone:"/> <TextBox Grid.Row="0" Grid.Column="1" x:Name="firstName" Text="{Binding FirstName}"/> <TextBox Grid.Row="1" Grid.Column="1" x:Name="lastName" Text="{Binding LastName}"/> <TextBox Grid.Row="2" Grid.Column="1" x:Name="email" Text="{Binding Email}"/> <TextBox Grid.Row="3" Grid.Column="1" x:Name="phone" Text="{Binding Phone}"/> </Grid> </UserControl> Notice that the view only contains layout and controls. All of the styling is expressed in App.xaml. The application The view needs an instance of the model to bind to. Our application will load this instance from a data source – most likely a database or a web service – and give it to the view. The view is hosted within a window. This is all accomplished in Application_Startup. DataSource dataSource = new DataSource(); this.MainWindow = new PersonWindow(); this.MainWindow.DataContext = dataSource.GetPerson(); this.MainWindow.Show(); Again, we are keeping it simple. There is no dependency injection. There is no service locator. If we see that we need that code, we will add it.
The code is extremely simple, and it worked out-of-the-box. So far we haven’t seen a need to implement INotifyPropertyChanged. Strictly speaking, that interface is not necessary for data binding to work. But very soon we will run into situations in which it is necessary. Also, we have not yet created a ViewModel. It is not strictly necessary for getting an application working. But again, we will soon see a situation in which it makes our code much cleaner. In part 2, we will add features to this application. Let’s see how those features look when we bind the view directly to the model. Table as queueWednesday, September 30th, 2009To play along at home, please download the script for SQL Server 2005. It may work on earlier versions, but I haven't tried it. Yesterday I said that the data is the queue. It is a mistake to separate the processing of data from the data itself. I proposed an architecture in which there is no workflow orchestration, there are only autonomous worker processes. These processes pick up work based on attributes of the objects on which they act, not based on any external queue. There are a small number of database patterns that make this possible. One that I often use is Table as Queue. Setup a test environment The database has two tables. The Order table holds orders that we want to process. If the order hasn't been processed, it has no confirmation number. If it has, it does. The Log table holds a log of all the steps the order processor has gone through. This will help us see how well we are doing. There are three stored procedures that we'll use. The InsertLoop stored procedure generates some test data. Run this one first. The ProcessLoop stored procedure simulates the ERP process. You'll want to open two query windows and enter "EXEC ProcessLoop" in both of them. Finally, the ViewLog procedure lets us see how we did. Anatomy of a queue procedure -- Get a work item
SET @orderId =
(SELECT TOP 1
OrderId
FROM [Order]
WHERE ConfirmationNumber IS NULL)
This ID has to be the primary key of the table. This is necessary for correct queuing behavior. If it is not the primary key, we will not get the correct locks later. To process the order, other details about that record will be required. These should be fetched separately by the returned ID. Do not try to combine these steps. Default isolation level Hit F5 on both of your ProcessLoop query windows. While this is running, run ViewLog. You'll see something like this:
Both of the SPIDs are processing all of the orders. This is clearly not what we want. We want only one SPID to process each order. Higher isolation level Make the following change to the ProcessLoop procedure: SET TRANSACTION ISOLATION LEVEL REPEATABLE READ Then start the two ProcessLoops again. Before long you will get the error "Transaction (Process ID 53) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction." The other process will still be running. Kill the remaining process. Close the window so that you can commit the transactions that got left open. Then open a new window and type "EXEC ProcessLoop" again to prepare for the next step. If you look at the log, you'll see only one of the SPIDs represented. The logs from the other one were rolled back with its transaction. What happened is that both SPIDs SELECTed the same record. The first one UPDATEd it, which prevented the second from doing so. When it tried to UPDATE, SQL recognized the deadlock and rolled it back. Update lock -- Get a work item
SET @orderId =
(SELECT TOP 1
OrderId
FROM [Order] WITH (UPDLOCK)
WHERE ConfirmationNumber IS NULL)
Now run the two processes and see what happens.
At first glance this looks good. Each order is processed by just one SPID. But look closely at the times. The two processes are taking turns. Each one enters SELECT, but then waits for the other one to commit its transaction before SELECT returns. Since we've requested an update lock, the higher transaction isolation level makes no difference. We can turn it back down to the default. Read past -- Get a work item
SET @orderId =
(SELECT TOP 1
OrderId
FROM [Order] WITH (UPDLOCK, READPAST)
WHERE ConfirmationNumber IS NULL)
With this hint in place, we get some good behavior.
Now the two processes are running concurrently. Each order is handled by only one process. There are no deadlocks. With this pattern, the data itself can be used as a queue. But you have to remember the details:
The data is the queueTuesday, September 29th, 2009Our eCommerce system uses BizTalk to process orders. The BizTalk orchestration keeps track of the status of the order. Queues keep track of communications between BizTalk and external systems, like the ERP. The database is updated at all points in the process so the web site reflects the current order status. This system is fragile. Problem 1: Diagnostics are scattered Problem 2: Things get out of sync Problem 3: Blocking Problem 4: Distributed transactions Here's my solution If we relied upon the Order table instead of using BizTalk and external queues, we would have a more consistent system. We could diagnose the entire workflow from the database. Having one shared system of record, services would never get out of sync. Certain patterns could be used to eliminate unnecessary blocking. And all transactions would be local. Broken down in this way, the system no longer has an overarching orchestration. You cannot open a designer and see the workflow. Instead, it has a number of autonomous processes that each move a unit of work further along the pipeline. Each process does its work in the same database. There is one cardinal rule that makes this possible. The action that a process performs must also remove it from its queue. A process runs a query to get a work item. It then performs some action on that work item. The outcome of that action is going to be a single database command. That command, whatever it is, must render the work item ineligible for the query. It is tempting to perform two database commands in the same transaction: record the results of the action and update the work item status. Avoid this pattern. This allows work items to become out of sync. Instead, design one database command that both records the result and disqualifies the work item from the query. Confirmation number SELECT TOP 1 OrderId, OrderDetails FROM [Order] WHERE ConfirmationNumber IS NULL And then recording the results of the action was: UPDATE [Order] SET ConfirmationNumber ? WHERE OrderId = ? This single UPDATE statement disqualifies the order from the SELECT statement. That means that the process will move the unit of work forward, but it can never be out of sync. Unfortunately, this SELECT ... UPDATE pattern is prone to blocking. We'll look at some patterns that satisfy this cardinal rule without blocking in future posts. MVVM and Linq to SQL the easy waySunday, August 9th, 2009Download the source code and follow along. The biggest challenge implementing the MVVM pattern is the View Model responding to changes in the Data Model. Usually, the View Model needs to subscribe to the PropertyChanged events fired by the Data Model, update its internal state, and then fire its own PropertyChanged events for the View. That's the hard way. The easy way is to use Update Controls. With Update Controls, you just decorate the Data Model and wrap the View Model. The library takes care of everything in between. Decorate a Linq to SQL data model Damien Guard has solved that problem. His open source project LINQ to SQL templates for T4 is incredibly easy to set up and start using. It drops straight into Visual Studio and replaces the build-in code generator with one that you control. With just a few edits to his provided T4 template, I replaced INotifyPropertyChanged with Independent sentries. I added a sentry for each single-valued property, and called OnGet() inside of the getter and OnSet() in the setter. I also added a sentry for each collection. They require OnGet() in the getter, and OnSet() when something is added or removed. Finally, I added a sentry per table, to take care of the top-level queries. For these, I call OnSet() on any insert, update, and delete. The final T4 template is in the example source code. Wrap the view model for WPF public Window1() { InitializeComponent(); // Create a data model and a navigation model. _blog = new Blog(); BlogNavigationModel navigationModel = new BlogNavigationModel(); // Put them both in a view model, then wrap it for the view. this.DataContext = ForView.Wrap(new BlogViewModel(_blog, navigationModel)); } We create a view model based on the decorated data model and a similarly decorated navigation model (more on that later). Then we let Update Controls wrap it up before we give it to the view. View model per scope We define one view model class for each of these three scopes. Each one takes constructor parameters to put itself in context. So the BlogViewModel takes a Blog, the ArticleViewModel takes a Blog and an Article, and the TagViewModel takes a Blog and a Tag. The DataContext property of a WPF control determines where it begins for data binding. If you don't set it, the control inherits it from its parent. If the control is an item in a list, then it is automatically set to an element of the ItemsSource. Finally, you can data bind to a property of its parent scope. Noteworthy uses all three techniques. Property per control attribute Navigation model per user context Where the user draws their conceptual boundary, we create a navigation model. A navigation model records the user's point-of-view as they navigate through the application. It keeps track of their selection and temporary input. All of the state in the navigation model is transient. Nothing is written to the database. Persistent state belongs in the data model. This keeps the view model completely stateless. The view model has only behavior, which depends upon the data model and the navigation model. Because the navigation model is transient, we just write fields, select them, and hit Ctrl+D, G to generate the properties. For example, here's the property that records the selected article. The part that I wrote by hand is highlighted: public class BlogNavigationModel { private Article _selectedArticle; #region Independent properties // Generated by Update Controls -------------------------------- private Independent _indSelectedArticle = new Independent(); /// <summary> /// The article for which to display details. /// </summary> public Article SelectedArticle { get { _indSelectedArticle.OnGet(); return _selectedArticle; } set { _indSelectedArticle.OnSet(); _selectedArticle = value; } } // End generated code -------------------------------- #endregion } The properties of the navigation model are always data model types, never view model types. The view model depends upon the navigation model, not vice-versa. Explore on your own
Expect future posts to return to this example and explore these points in more detail. |