Home > Articles > Programming > Visual Studio

  • Print
  • + Share This
From the author of Working with Data

Working with Data

Our mobile client will be able to perform classic operations such as reading, deleting, and inserting data that will be saved back to the original LightSwitch data source via the OData service. The first task is to load data for reading. Listing 5 demonstrates how to create a couple of methods that load customers, orders, and the event handlers for the DataServiceCollection.LoadCompleted event.

Listing 5—Loading data asynchronously.

'Querying the data service for the full list of items
'and loading data asynchronously
Private Sub loadCustomers()
    Dim query = From cust In Me.applicationData.Customers
                Order By cust.CompanyName Descending
                Select cust

    customers.LoadAsync(query)
End Sub

Private Sub loadOrders()
    orders.LoadAsync(New Uri("http://localhost/ExposingOData/ApplicationData.svc/Orders", UriKind.Absolute))
End Sub

Private Sub orders_LoadCompleted(sender As Object, e As LoadCompletedEventArgs)
    'If the feed exposes paged data, load the next chunk of data
    If e.Error Is Nothing Then
        If Me.orders.Continuation IsNot Nothing Then
            Me.orders.LoadNextPartialSetAsync()
        Else
            'Otherwise simply assign the data collection as the
            'data source of the ContentPanel grid
            Me.ContentPanel.DataContext = Me.orders
        End If
    Else
        MessageBox.Show(e.Error.Message)
    End If
End Sub

Private Sub customers_LoadCompleted(sender As Object, e As LoadCompletedEventArgs)
    If e.Error Is Nothing Then
        'No assignment of the customers collection
        'because it will not be displayed in the UI
        If Me.customers.Continuation IsNot Nothing Then
            Me.customers.LoadNextPartialSetAsync()
        End If
    Else
        MessageBox.Show(e.Error.Message)
    End If
End Sub

The DataServiceCollection class exposes an instance method called LoadAsync that loads data asynchronously, meaning that the user interface remains responsive (which is very important in Windows Phone apps). LoadAsync can receive as an argument either the result of a Language Integrated Query (LINQ), and is therefore of type IQueryable(Of T), or the URI of the entity set. The first approach is useful if you want to query an entity set with filters or sorting conditions; the second is preferable when you want to load (or reload) data from the actual data source, instead of using an in-memory collection.

Once the load operation completes, the runtime raises a LoadCompleted event. It might happen that an OData feed exposes paged data. In this particular case, we invoke the LoadNextPartialSetAsync method. However, if data has been fully loaded, the data is assigned to the ContentPanel object as the data source for presentation controls.

The next step is adding code for deleting and adding orders. Deleting a selected order is very simple, because you just need to retrieve the current object from the ListBox control, convert it to the appropriate type, and then mark it for deletion. Inserting an order is also easy, but it would require designing a specific page where the user can enter custom information. For this reason (and for the sake of keeping this article's examples relatively simple), the code presented here creates a new order, programmatically supplying hard-coded values at runtime. Listing 6 shows the code for deleting and adding orders.

Listing 6—Deleting and inserting order instances.

'Delete the selected order
'If you are passing credentials of a user that is not authorized
'the code throws a NotAuthorizedException
Private Sub DeleteButton_Click(sender As System.Object, e As System.EventArgs)
    Dim currentOrder = TryCast(Me.OrdersListBox.SelectedItem, OrdersServiceReference.Order)

    If currentOrder IsNot Nothing Then
        Me.orders.Remove(currentOrder)
    End If
End Sub

Private Sub InsertButton_Click(sender As System.Object, e As System.EventArgs)
    'Hard coding the creation of a new order
    'Assuming there is already a customer with the specified name
    Dim customerInstance = customers.Where(Function(c) c.CompanyName.ToLower.Contains("del sole")).tOrDefault

    Dim newOrder As New OrdersServiceReference.Order
    With newOrder
        .OrderDate = Date.Today
        .Description = "Order of Natural Water"
        .ShippedDate = Date.Today.AddDays(1)
        .RequiredDate = Date.Today.AddDays(2)
        .Customer = customerInstance
    End With

    Me.orders.Add(newOrder)
End Sub

You delete and add items directly over the DataServiceCollection(Of T), exactly as you would do in any other collections, by using methods like Remove and Add. If you wanted to update an object, you could first get the instance of that object and then edit its properties. Actually, the ApplicationData class (and more generally proxy classes representing data sources) also exposes the DeleteObject, AddObject, and UpdateObject methods. These methods require the instance of the object that you want to delete, add, or edit. They work against the data service, not with the DataServiceCollection, so in the case of data-binding it wouldn't be a good choice, because bindings wouldn't update automatically.

Whatever your choice is, invoking such methods doesn't also save changes back to the data source; instead, they just keep track of changes in memory until a save operation is invoked. In our specific case for this article, entities are removed from and added to an in-memory collection, but changes are not sent to the data service until you invoke a save operation. Saving data is also an asynchronous operation. Since we provided a Save button, let's handle the Click event for that button now, as demonstrated in Listing 7.

Listing 7—Saving changes through the OData service.

Private Sub SaveButton_Click(sender As System.Object, e As System.EventArgs)
    'Start saving asynchronously
    Me.applicationData.BeginSaveChanges(SaveChangesOptions.Batch,
     AddressOf OnChangesSaved, Me.applicationData)
End Sub

Private Sub OnChangesSaved(result As IAsyncResult)
    ''Use the dispatcher to run the operation inside the appropriate thread
    Dispatcher.BeginInvoke(Sub()
                               'Get the instance of the application data
                               Me.applicationData = CType(result.AsyncState, ApplicationData)
                               Try
                                   'Finalize the save operation
                                   Me.applicationData.EndSaveChanges(result)
                                   'Reload data for data-binding
                                   loadOrders()
                               Catch ex As DataServiceRequestException
                                   MessageBox.Show(String.Format("Data service error: {0}", ex.Message))
                               Catch ex As Exception
                                   MessageBox.Show(String.Format("Error: {0}", ex.Message))
                               End Try
                           End Sub)

End Sub

You invoke BeginSaveChanges to start an asynchronous operation. When the operation is completed, a callback is invoked; here you'll finalize the save operation by invoking EndSaveChanges, and reload data for data-binding.

  • + Share This
  • 🔖 Save To Your Account