Implementing Master-Detail Scenarios with Infragistics UltraGrid, UltraDataChart and Entity Framework

Infragistics Windows Form controls offer opportunities to cover different scenarios, representing data in your desktop applications. It is one of the best, most extensible third party controls that I have ever used for UI development. Some of the scenarios are more complex and you need to consider some things during the implementation.

One of the most often seen cases is when we have master-detail scenario: master table (respectively parent entity) and detail/child table (child entity). 

WiltraGrid supports out of the box ADO.Net based data source – DataTables in DataSets, but last several years other frameworks like Entitry Framework are the best choice for rapid development, related to the line of business scenarios

This blog will demonstrate how to do master-detail scenarios with UltraGrid, Entity Framework and some other components from Infragistics Winforms like UltraDataChart. First, let’s choose some sample data to demonstrate the mentioned above scenarios.


Creating a Simple Master-Detail Model

In order to illustrate these loading techniques let's create a simple one-to-many example using our favorite database, Northwind. Using Visual Studio 2013 we can add a new item to the project and selected Entity Data Model, chose the "Generate from Database" option, and selected Categories and Products tables from Northwind.

Below you'll see the sample Entity Data Model (EDM):

UltraGrid-Master-Detail-Pic01[1]

Entity Framework supports the following three methods to load related data:

  • Eager Loading
  • Lazy Loading
  • Explicit Loading

 

Eager Loading Entities

In Eager Loading, all relevant data for an entity is loaded at the time of the query of the entity in the context object. Eager Loading can be done by using the "Include" method. To perform Eager Loading, Lazy Loading must be disabled. Lazy Loading is enabled by default in Entity Framework.

We can also eagerly load multiple levels of related entities. In the following example, it loads the related entity Department, Employee Master and Detail.

Often we want to have only one query to have all data – it is good if we don't have huge amounts of data. In the scenario above we always want to display the related Categories with the Products so it would be better to make a single call to the database to retrieve the Category and the Products. In that case we can use the Include method that is available on an entity and we add this to our query in our form's Load:

 1: #region members
 2:  
 3: ObservableCollection data;
 4: static NORTHWNDEntities model = new NORTHWNDEntities();
 5: public static int NumberOfProducts;
 6:  
 7: #endregion members
 8: public Form1()
 9: {
 10:     InitializeComponent();
 11:     data = new ObservableCollection((model.Categories.Include("Products")).ToList());
 12:  
 13:     ultraProductGrid.DataSource = data;
 14:     ultraProductGrid.DisplayLayout.Override.SelectTypeRow = SelectType.Single;
 15:  
 16: }

 

We will use Eager Loading for our demo, but consider our other options:

Lazy loading implementation:

Implementing Lazy Loading works well when you only need to make a few additional calls for the related data or the data is optional (like triggered by a user action). On the other hand, if you know you will always need the related data then it is probably more efficient to load the related entities in a single call. This is called Eager Loading -- there is more data returned to you but there is less chit-chat between the client and the database.

Lazy Loading means delay loading the related entities. In Lazy Loading, a related entity or collection of entities is loaded from the database for the first time that a property is referred or the entity is accessed.

 1: using (var context = new Entities())
 2: {
 3:     context.ContextOptions.LazyLoadingEnabled = true;
 4:  
 5:     Console.WriteLine("Lazy Lading Example....");
 6:     var dep = context.DepartmentMasters.Where(f => f.DepartmentId == 1).FirstOrDefault();
 7:     foreach (var emp in dep.EmployeeMasters)
 8:     {
 9:         Console.WriteLine("Code: " + emp.Code + " Email Address:" + emp.EmployeeDetail.PersonalEmail);
 10:     }
 11:     Console.ReadKey();
 12: }

 

Explicit Loading

If Lazy Loading is disabled then it is still possible to fetch the related entities without the use of Eager Loading. It is possible with Explicit Loading. To explicitly retrieve the related entities from the database we can use the "Load" method.

To explicitly retrieve the related entities from the database, we can use the "Load" method. The following will explicitly load one-to-many related entities:

 1: static void Main(string[] args)
 2: {
 3:     using (var context = new Entities())
 4:     {
 5:         var dep = context.DepartmentMasters.Where(p => p.DepartmentId ==    1).FirstOrDefault();
 6:         Console.WriteLine("Department Employees are not currently loaded");
 7:         if (!dep.EmployeeMasters.IsLoaded)
 8:         {
 9:             dep.EmployeeMasters.Load();
 10:             Console.WriteLine("Department Employees load complete");
 11:             foreach (var emp in dep.EmployeeMasters)
 12:             {
 13:                 Console.WriteLine(emp.Code);
 14:             }
 15:          }
 16:          Console.ReadKey();
 17:     }
 18: }  

 

Let’s continue with the eager loading scenario.

Receive the list with child records

This is pretty easy if you need to handle child records of the selected row to use the AfterRowActivate event:

 1: private void ultraProductGrid_AfterRowActivate(object sender, EventArgs e)
 2: {
 3:     Category currCategory = null;
 4:     var oRow = ultraProductGrid.ActiveRow;
 5:     if (oRow != null)
 6:     {
 7:         currCategory = oRow.ListObject as Category;
 8:         if (currCategory == null)
 9:         {
 10:             return;
 11:         }
 12:         if (currCategory == null) { return; }
 13:         var products = currCategory.Products.ToList();
 14:  
 15:     }
 16: }

 

Update the UltraDataChart

UltraDataChart is one of the most popular data visualization components for Windows Forms. The UltraDataChart offers powerful ways to interact with data, such as zooming, trendlines and chart synchronization. In addition to all the types supported by the XamChart, UltraDataChart supports polar and radial series types.

You need to create axes and series using data from the child records:

 1: var xAxis = new CategoryXAxis
 2: {
 3:     Label = "ProductName",
 4:     DataSource = products
 5: };
 6:  
 7: var yAxis = new NumericYAxis();
 8:  
 9: LineSeries series = new LineSeries();
 10: series.XAxis = xAxis;
 11: series.YAxis = yAxis;
 12: series.ValueMemberPath = "UnitsOnOrder";
 13: series.DataSource = products;
 14:  
 15: ultraProductsDataChart.Axes.Clear();
 16: ultraProductsDataChart.Series.Clear();
 17:  
 18:  
 19: ultraProductsDataChart.Axes.Add(xAxis);
 20: ultraProductsDataChart.Axes.Add(yAxis);
 21: ultraProductsDataChart.Series.Add(series);

 

Bind labels

It is possible to use different techniques to bind the label’s text to the specific value. The current sample offers the approach to create a property in Peoperties.Settings:

 1: Properties.Settings.Default.CategoryName = currCategory.CategoryName;
 2: if (currCategory == null) { return; }
 3: var products = currCategory.Products.ToList();
 4: Properties.Settings.Default.ProductsCount = products.Count().ToString();

 

The whole code of the method is available here:

 1: private void ultraProductGrid_AfterRowActivate(object sender, EventArgs e)
 2: {
 3:     Category currCategory = null;
 4:     var oRow = ultraProductGrid.ActiveRow;
 5:     if (oRow != null)
 6:     {
 7:         currCategory = oRow.ListObject as Category;
 8:         if (currCategory == null)
 9:         {
 10:             return;
 11:         }
 12:         Properties.Settings.Default.CategoryName = currCategory.CategoryName;
 13:         if (currCategory == null) { return; }
 14:         var products = currCategory.Products.ToList();
 15:  
 16:         Properties.Settings.Default.ProductsCount = products.Count().ToString();
 17:  
 18:         var xAxis = new CategoryXAxis
 19:         {
 20:             Label = "ProductName",
 21:             DataSource = products
 22:         };
 23:  
 24:         var yAxis = new NumericYAxis();
 25:  
 26:         LineSeries series = new LineSeries();
 27:         series.XAxis = xAxis;
 28:         series.YAxis = yAxis;
 29:         series.ValueMemberPath = "UnitsOnOrder";
 30:         series.DataSource = products;
 31:  
 32:         ultraProductsDataChart.Axes.Clear();
 33:         ultraProductsDataChart.Series.Clear();
 34:  
 35:  
 36:         ultraProductsDataChart.Axes.Add(xAxis);
 37:         ultraProductsDataChart.Axes.Add(yAxis);
 38:         ultraProductsDataChart.Series.Add(series);
 39:  
 40:     }
 41: }

 

Implementation

Implemented functionalities are available in the sample that is available for download here. You can see screenshots from the demo below:

UltraGrid-Master-Detail-Pic03a[1]

 

UltraGrid supports out of the box visualization of the rows from related tables, as you can see here.

UltraGrid-Master-Detail-Pic04a[1]

 

This article covers just some of the basic Master Detail scenarios, realized with Infragistics WinForms grid and Entity Framework - and to make the most of this post, be sure to download the source code of this sample here.

You'll also need the Northwind sample database, which you can get in SQLServer 2008 or newer through the CodePlex website. It is also possible also to download a version that's compatible with older versions of Microsoft SQL server from the Microsoft download center.

To play around with the Infragistics Windows Forms dashboards on your own, be sure to get Infragistics Ultimate and see the chart in action in our latest sample application by clicking the banner below!