WAQS: Querying a lot of entities

7 reasons to use WAQS

WAQS documentation

 

The waiting issue

When you load 100 000 entities to show them in a ListBox for example, user experience is very bad if application freezes with a Not responding message.

How to avoid application freezing

To avoid application freezing, the idea is to not wait from the server when you send it a query. So the idea is to use an asynchronous call and async / await syntax helps us to make it easy.

With WAQS, querying is use an asynchronous way by design.

However, the user may wait a long time before showing data on the ListBox. In addition, if you receive to many entities, WCF can fails based on its configuration.

In order to fix it, WAQS proposes to load data by step. So, for example, we could load the 100 first entities and then the 100 next ones, etc until loading all of them.

In addition, using this way allows you to cancel loading anytime in the process.

ByStepQuery

WAQS already implements this process with ByStepQuery class.

Class ByStepQuery<T> exposes an IObservable<T>. This one notifies caller anytime new entities are loaded.

The fact to expose an IObservable allows developers to do what they want. However, in most cases, we just want an ObservableCollection bound on the view.

So ByStepQuery also exposes a Load method that fills an ObservableCollection property: Items.

Note that current version of Rx is no usable with PCL. So for PCL, WAQS uses a basic loop that fills the ObservableCollection Items.

So, in the ViewModel you just have to expose a ByStepQuery (or its ObservableCollection) and to bind on Items property on the view (or directly to the VM ObservableCollection property).

In order to be able to use it very easily, you can use an extension method “ToByStepQuery” that transforms an IAsyncQueryable into ByStepQuery.

private ByStepQuery<OrderDetailDTO> _orderDetails;
public ByStepQuery<OrderDetailDTO> OrderDetails
{
    get
    {
        return _orderDetails ??
(_orderDetails = (from od in _context.OrderDetails.AsAsyncQueryable()
                              let companyName = od.Order.Customer.CompanyName
                              let orderDate = od.Order.OrderDate
                              orderby companyName, orderDate descending
                              select new OrderDetailDTO { CompanyName = companyName, OrderDate = orderDate, Quantity = od.Quantity, UnitPrice = od.UnitPrice })
.ToByStepQuery(100).Load());
    }
}

public void Cancel()
{
    OrderDetails.Cancel();
}

With this OrderDetailDTO class:

public class OrderDetailDTO
{
    public string CompanyName { get; set; }
    public DateTime OrderDate { get; set; }
    public double UnitPrice { get; set; }
    public short Quantity { get; set; }
}

Now, we can bind it with this xaml:

<Window x:Class="WAQSByStepQuery.Client.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        Title="MainWindow" Height="350" Width="525">
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto" />
             <RowDefinition />
         </Grid.RowDefinitions>
         <Button Content="Cancel"
            Padding="5">
             <i:Interaction.Triggers>
                 <i:EventTrigger EventName="Click">
                     <ei:CallMethodAction TargetObject="{Binding}"
                                        MethodName="Cancel" />
                 </i:EventTrigger>
             </i:Interaction.Triggers>
         </Button>
         <ListBox Grid.Row="1"
                ItemsSource="{Binding OrderDetails.Items}">
             <ListBox.ItemTemplate>
                 <DataTemplate>
                     <StackPanel Orientation="Horizontal">
                         <TextBlock Text="{Binding CompanyName}" />
                         <TextBlock Margin="5,0"
                                Text="{Binding OrderDate}" />
                         <TextBlock Margin="5,0"
                                Text="{Binding Quantity}" />
                         <TextBlock Margin="5,0"
                                Text="{Binding UnitPrice}" />
                     </StackPanel>
                 </DataTemplate>
             </ListBox.ItemTemplate>
         </ListBox>
     </Grid> </Window>

Note that you can replace the Event Trigger (that is not supported by W8 / WP8 yet) by an ICommand.

This entry was posted in 12253, 16868. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*