PCTradeOffice

The PCTradeOffice sample demonstrates how a complex application might use Data Abstract for .NET to provide access to the PCTrade database (accessed through the PCTrade schema) and allow the user to browse and edit the content much like a "real" client application would. Principally the sample uses DA LINQ to interact with the schema data.

Getting Started

The sample is typically located in C:\Users\Public\Documents\RemObjects Samples\Data Abstract for .NET\C#\PCTradeOffice, though you may have installed the Data Abstract for .NET SDK and it's samples in another location.

To build it, you will of course need Visual Studio, and like all the samples provided with Data Abstract for .NET you will need to be running Relativity Server with the DASamples Domain and the PCTrade Schema available.

Running the Sample

This sample allows you to view & alter the content of a number of different tables, from the point of view of users who have different levels of access. When the sample first starts it presents the main UI and a login dialog with three users that can be selected.

Each of three users have different access levels which provide different abilities:

  • Mollie Bennet the Managing Director of the fictional company. She has access to all of the data and can view all of of the available views. In the "Orders" view she has access to all of the data unlike the other two users. She also can view the special "Sales Report" data.
  • Gale Dalton who is the Income Manager, she is only able to view the "Orders", "Price List" and "Providers". Her "Orders" table is filtered to only show the orders that she has originated.
  • Sandy Manning who is the Sales Manager, she is can only view the "Orders" and "Clients" tables.

Simply click on the user you want and then press the "Login" button. Once logged in you will have a number of the tab like views available. Each one presents data retrieved from multiple tables in the remote schema. Note not all of those views are available to every user in the system.

  • The Users tab provides a means to switch to different users, as well as see the access rights for that user. When you press the "Change user" button the login dialog is again presented.

  • The Orders view displays data retrieved from the "Orders", "OrderDetails", "PriceList" and "RestReport" tables. Many of the fields on display are added using Lookup and Calculated fields. The data returned from the server is filtered based on the user accessing the server using Business Rules Scripting and Dynamic Where.

  • The PriceList view takes data from the "Products" and "PriceList" tables are presents the data in a tree like structure.

  • The Clients view displays a table of all of the clients in the "Clients" table, and allows the user to add, edit or delete them.

  • The Providers view similarly displays a table of all of the stock providers in the "Providers" table and allows the user to add, edit or delete them.

  • The Reports view is only available to the managing director user, it uses a special "SalesReport" table in the PCTrade schema that uses custom SQL to pull together data from multiple schema tables and return that. The "SalesReport" table can be passed two parameters (a start and end date) that then filters the data based on those dates.

Examining the Code

This section gives an overview of the classes that makes up this sample as well as specific details related to using the classes provided by Data Abstract for .NET.

App Structure

The sample is built around many different classes though the principle class is DataModule as it handles the interaction with the instance of Relativity Server including retrieving data, logging into and out of the server and retrieving the profile image for the logged in user.

The PCTrade_TableDefinitions class is machine generated from the PCTrade.relativityClient file. It provides concrete classes for the tables in the schema and their rows. Those classes are used throughout the sample for displaying and manipulating field data.

The MainWindow defines the basic user interface with the tabs, and works in concert with MainWindowViewModel which creates an instance of DataModule, creates view models for each of the tab views available in the sample, and handles other user interface related operations like determining which tab will be visible first after a user logs in.

Each tab ("Orders", "PriceList", "Clients", "Providers" and "Reports") has a "Repository" class which uses the DataModule and the LinqRemoteDataAdapter to provide methods for inserting, updating and deleting a row, as well as selecting a specific row or all rows. The tab also has "View" and "ViewModel" classes which handle defining the tab's visual interface and the code to handle the user interaction.

Using LinqRemoteDataAdapter

Rather than using the RemoteDataAdapter that other samples use, this sample uses the LinqRemoteDataAdapter class. It, like the RemoteDataAdapter, is a Data Adapter that handles the communication between the client program and the server. Configuration the connection and handling login is identical between the classes, but how they interact with the schema and tables is different. Note that the LinqRemoteDataAdapter adapter does not support Dynamic Where or Dynamic Select per se, but you can use DA LINQ to achieve the same results.

The LinqRemoteDataAdapter also handles tracking the changes to the table data (for instance adding a new row, or deleting an existing one) until the ApplyChanges method is called. At this point all local changes will be applied to the server.

Retrieving Data with DA LINQ

The sample uses DA LINQ and the LinqRemoteDataAdapter throughout to retrieve the data from the remote schema.

A typical DA LINQ query is shown below. The first part retrieves the table using the GetTable of LinqRemoteDataAdapter, which will be the data source for the remainder of the DA LINQ query. You can then use standard LINQ queries to work with the data. In this sample, the DA LINQ query selects all the rows and fields from the Products table. After the query is complete, the sample converts the results to a List object.

 

// line taken from DataModule.cs - public List<Products> ProductList property
fProductsList = (from t in DataAdapter.GetTable<Products>() select t).ToList<Products>();

Applying Changes to the server

The LinqRemoteDataAdapter data adapter will track all of the changes to the data until they are sent to the server. To send the changes call the ApplyChanges method.

In this sample the ApplyChanges method is called immediately after a row has been inserted into a table, updated or deleted.

 

// line taken from ClientsRepository.cs - public override void Insert(Clients entity)
DataModule.SharedInstance.DataAdapter.ApplyChanges();

Adding a row

Adding a new row when using LinqRemoteDataAdapter is different than when normally using Data Abstract. Instead of adding the row to a DataTable and using a DataSet or DeltaChange object to store the data and apply those changes to the server, you instead use concrete data classes which map to a row in the table and then pass those to the Data Adapter.

After you've created the data object (here an instance of the Clients), it needs to be passed to the InsertRow method of LinqRemoteDataAdapter. The LinqRemoteDataAdapter data adapter will track all of the changes to the data and apply them to the server when the ApplyChanges method is called.

 

// line taken from ClientsRepository.cs - public override void Insert(Clients entity)
DataModule.SharedInstance.DataAdapter.InsertRow<Clients>(entity);

Updating a row

Updating an existing row is as simple as updating the properties of the data object representing the row and then passing that updated object to the UpdateRow method of LinqRemoteDataAdapter.

The LinqRemoteDataAdapter data adapter will track all of the changes to the data and apply them to the server when the ApplyChanges method is called.

 

// line taken from ClientsRepository.cs - public override void Update(Clients entity)
DataModule.SharedInstance.DataAdapter.UpdateRow<Clients>(entity);

Deleting a row

To delete an existing row pass the data object that represents the row you wish to delete to the DeleteRow method of LinqRemoteDataAdapter.

 

// line taken from ClientsRepository.cs - public override void Delete(Clients entity)
DataModule.SharedInstance.DataAdapter.DeleteRow<Clients>(entity);