Maintaining the Lifecycle of the Context with the EntityDataSource Component
This section discusses how to maintain the lifecycle of the ObjectContext/DbContext when using the EntityDataSource
component. The provided examples and code snippets assume an existing Entity Data Model of the Adventure Works sample database with the following structure:
One possible approach to connect to an Entity Data Model without using the EntityDataSource
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 ObjectDataSource
to connect to that business object, as shown in the following code snippet:
var objectDataSource = new Telerik.Reporting.ObjectDataSource();
objectDataSource.DataSource = typeof(SampleBusinessObject);
objectDataSource.DataMember = "GetProducts";
var report = new Report1();
report.DataSource = objectDataSource;
Dim objectDataSource As Telerik.Reporting.ObjectDataSource = New Telerik.Reporting.ObjectDataSource()
objectDataSource.DataSource = GetType(SampleBusinessObject)
objectDataSource.DataMember = "GetProducts"
Dim report As New Report1()
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 us 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 the ADO.NET Entity Framework 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 ObjectContext/DbContext is already destroyed when evaluating the expression, so lazy loading is no longer possible. One of the greatest advantages of the EntityDataSource
component is that it can maintain the lifecycle of the ObjectContext/DbContext automatically, so scenarios like the previous one are guaranteed to work as expected. When specifying a Type
for the Context
property, EntityDataSource
creates internally a new instance of the ObjectContext/DbContext with the given type, keeps it alive for the duration of the report generation process, and then destroys it automatically when it is no longer needed by the reporting engine. The following code snippet accomplishes the previous task with the help of the EntityDataSource
component:
var entityDataSource = new Telerik.Reporting.EntityDataSource();
entityDataSource.Context = typeof(AdventureWorksEntities);
entityDataSource.ContextMember = "Products";
var report = new Report1();
report.DataSource = entityDataSource;
Dim entityDataSource As New Telerik.Reporting.EntityDataSource()
entityDataSource.Context = GetType(AdventureWorksEntities)
entityDataSource.ContextMember = "Products"
Dim report As New Report1()
report.DataSource = entityDataSource
If you have already implemented your own mechanism for maintaining the lifecycle of the ObjectContext/DbContext you can continue using the EntityDataSource
component. In this case however you need to specify a live instance of your ObjectContext/DbContext to the Context
property as demonstrated here:
var entityDataSource = new Telerik.Reporting.EntityDataSource();
var context = new AdventureWorksEntities();
entityDataSource.Context = context;
entityDataSource.ContextMember = "Products";
var report = new Report1();
report.DataSource = entityDataSource;
// You have to dispose the Context explicitly when done with the report.
context.Dispose();
Dim entityDataSource As New Telerik.Reporting.EntityDataSource()
Dim context As New AdventureWorksEntities()
entityDataSource.Context = context
entityDataSource.ContextMember = "Products"
Dim report As New Report1()
report.DataSource = entityDataSource
' You have to dispose the context explicitly when done with the report.
context.Dispose()