How to: Maintain the Lifecycle of the OpenAccessContext
This topic discusses how to maintain the lifecycle of the OpenAccessContext when using the OpenAccessDataSource component. The provided examples and code snippets assume an existing Telerik Data Access Model of the Product schema from the Adventure Works sample database.
One naïve approach to connect to an Telerik Data Access Model without using the OpenAccessDataSource component is to create a custom business object with a method that retrieves the necessary entities for the report. The sample code below defines a method that retrieves information about all products:
public class SampleBusinessObject
{
public System.Collections.Generic.List<Product> GetProducts()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
return context.Products.ToList();
}
}
}
Public Class SampleBusinessObject
Public Function GetProducts() As System.Collections.Generic.List(Of Product)
Using context As AdventureWorksEntities = New AdventureWorksEntities()
Return context.Products.ToList()
End Using
End Function
End Class
Then you can use OpenAccessDataSource to connect to that business object, as shown in the following code snippet:
Telerik.Reporting.ObjectDataSource objectDataSource = new Telerik.Reporting.ObjectDataSource();
objectDataSource.DataSource = typeof(SampleBusinessObject);
objectDataSource.DataMember = "GetProducts";
Telerik.Reporting.Report report = new Telerik.Reporting.Report();
report.DataSource = objectDataSource;
Dim objectDataSource As Telerik.Reporting.ObjectDataSource =
New Telerik.Reporting.ObjectDataSource()
objectDataSource.DataSource = GetType(SampleBusinessObject)
objectDataSource.DataMember = "GetProducts"
Dim report As Telerik.Reporting.Report = New Telerik.Reporting.Report()
report.DataSource = objectDataSource
The problem with this approach is that it is not guaranteed to work in all possible scenarios. Simple expressions accessing primitive properties of the Product entity might work as expected:
=Fields.Name
However, let's consider the following expression that is intended to obtain the category of a given product:
=Fields.ProductSubcategory.ProductCategory.Name
The above expression relies upon the lazy loading mechanism of Telerik Data Access to obtain the ProductSubcategory entity for the current Product entity via the corresponding relation property, and then the ProductCategory entity for the current ProductSubcategory entity. This is not guaranteed to work because the OpenAccessContext is already destroyed when evaluating the expression, so lazy loading is no longer possible.
One of the greatest advantages of the OpenAccessDataSource component is that it can automatically maintain the lifecycle of the OpenAccessContext, so scenarios like the previous one are guaranteed to work as expected. When specifying a Type for the OpenAccessContext property, OpenAccessDataSource internally creates a new instance of the OpenAccessContext with the given type, keeps it alive for the duration of the report generation process, and then automatically destroys it when it is no longer needed by the reporting engine.
The following code snippet accomplishes the previous task with the help of the OpenAccessDataSource component:
Telerik.Reporting.OpenAccessDataSource openAccessDataSource =
new Telerik.Reporting.OpenAccessDataSource();
openAccessDataSource.ObjectContext = typeof(AdventureWorksEntities);
openAccessDataSource.ObjectContextMember = "Products";
Telerik.Reporting.Report report = new Telerik.Reporting.Report();
report.DataSource = openAccessDataSource;
Dim openAccessDataSource As Telerik.Reporting.OpenAccessDataSource =
New Telerik.Reporting.OpenAccessDataSource()
openAccessDataSource.ObjectContext = GetType(AdventureWorksEntities)
openAccessDataSource.ObjectContextMember = "Products"
Dim report As Telerik.Reporting.Report = New Telerik.Reporting.Report()
report.DataSource = openAccessDataSource
If you have already implemented your own mechanism for maintaining the lifecycle of the OpenAccessContext you can continue using the OpenAccessDataSource component. In this case, you need to specify a live instance of your OpenAccessContext to the ObjectContext property as demonstrated here:
Telerik.Reporting.OpenAccessDataSource openAccessDataSource =
new Telerik.Reporting.OpenAccessDataSource();
AdventureWorksEntities openAccessContext = new AdventureWorksEntities();
openAccessDataSource.ObjectContext = openAccessContext;
openAccessDataSource.ObjectContextMember = "Products";
Telerik.Reporting.Report report = new Telerik.Reporting.Report();
report.DataSource = openAccessDataSource;
// You have to dispose the OpenAccessContext explicitly when done with the report.
openAccessContext.Dispose();
Dim openAccessDataSource As Telerik.Reporting.OpenAccessDataSource =
New Telerik.Reporting.OpenAccessDataSource()
Dim openAccessContext As AdventureWorksEntities = New AdventureWorksEntities()
openAccessDataSource.ObjectContext = openAccessContext
openAccessDataSource.ObjectContextMember = "Products"
Dim report As Telerik.Reporting.Report = New Telerik.Reporting.Report()
report.DataSource = openAccessDataSource
' You have to dispose the OpenAccessContext explicitly when done with the report.
openAccessContext.Dispose()