Telerik OpenAccess Classic

Telerik OpenAccess ORM Send comments on this topic.
Best Practices for Using FetchPlans
See Also
Programmer's Guide > OpenAccess ORM Classic (Old API) > Programming With OpenAccess > FetchPlans and FetchGroups > Best Practices for Using FetchPlans

Glossary Item Box

This documentation article is a legacy resource describing the functionality of the deprecated OpenAccess Classic only. The contemporary documentation of Telerik OpenAccess ORM is available here.

FetchPlans are very powerful mechanism of Telerik OpenAccess ORM. They allow the user to specify fetching from the database of only the necessary fields. This approach could considerable improve the performance of the queries used for reading operations.

Consider the following data model:

C# Copy Code
[Telerik.OpenAccess.Persistent(IdentityField = "customerID")]
public partial class Customer
{
   [Telerik.OpenAccess.FetchField(
"Customers")]
   
private string customerID;
   
private string address;
   
private string city;
   
private string companyName;
   [Telerik.OpenAccess.FetchField(
"Customers")]
   
private string contactName;
   
private string contactTitle;
   [Telerik.OpenAccess.FetchField(
"Customers")]
   
private string country;
   
private string fax;
   
private string phone;
   
private string postalCode;
   
private string region;
}
VB.NET Copy Code
<Telerik.OpenAccess.Persistent(IdentityField := "customerID")> _
Partial Public Class Customer
    <Telerik.OpenAccess.FetchField("Customers")> _
    Private customerID As String
    Private address As String
    Private city As String
    Private companyName As String
    <Telerik.OpenAccess.FetchField("Customers")> _
    Private contactName As String
    Private contactTitle As String
    <Telerik.OpenAccess.FetchField("Customers")> _
    Private country As String
    Private fax As String
    Private phone As String
    Private postalCode As String
    Private region As String
End Class

The [FetchField] attribute is used to mark which fields are included in a named FetchGroup. There are several ways of using  Fetch Plans:

Using FetchPlans with OpenAccessDataSource

To apply this approach inside your solution follow these steps:

  • Provide an event handler for the ContextCreated event of the OpenAccessDataSource. There you should specify the FetchPlan as shown below:
    C# Copy Code
    protected void OnContextCreated(object sender, OpenAccessDataSourceContextCreatedEventArgs e)
    {
       e.Context.FetchPlan.Add(
    "FetchGroupName");
    }
    VB.NET Copy Code
    Sub OnContextCreated(ByVal sender As Object, ByVal e As OpenAccessDataSourceContextCreatedEventArgs)
     e.Context.FetchPlan.Add("Customers")
    End Sub
  • Bind only the columns from the fetch group inside the UI control (for example a RadGrid). Otherwise additional calls to the database will be made.
  • If the classes are reverse mapped or the concurrency control (link to the article) is not needed for this data, set the StoreOriginalValuesInViewState (link to the article) property of the OpenAccessDataSource to false. The reason for this step is that the OpenAccessDataSource implementation of the default concurrency mechanism checks all the fields for concurrency violations. That leads to triggering the lazy-loading mechanism that fetches the whole object from the database.

Using FetchPlans from Code-Behind

To use a fetch group, it should be added to a fetch plan by calling the FetchPlan.Add() method of the object scope. By default the fetch plan contains only the "Default" fetch group which retrieves all value fields of the persistent objects.

C# Copy Code
IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope();
scope.FetchPlan.Add("Customers");
var result = from c
in scope.Extent<Customer>()
               select c;
foreach (Customer c in result.ToList())
{
  Console.WriteLine(String.Format(
"{0} {1} {2}", c.CustomerID, c.ContactName, c.Country));
}   
VB.NET Copy Code
Dim scope As IObjectScope = ObjectScopeProvider1.GetNewObjectScope()
scope.FetchPlan.Add("Customers")
Dim result = From c In scope.Extent(Of Customer)() _
             Select c

For Each c As Customer In result.ToList()
   Console.WriteLine(String.Format("{0} {1} {2}", c.CustomerID, c.ContactName, c.Country))
Next c

It is not a good practice to clear the current fetch plan before adding the new fetch groups. This is done by the scope.FetchPlan.Clear() method. The fetch plan by default contains only the "Default" fetch group. The "Default" fetch group tells the object scope to retrieve all the value fields of an object and only the ID’s of the reference ones.

In case you need to clear the current fetch plan by invoking the FetchPlan.Clear() method, the Default fetch group will be also removed. In this case you should explicitly set which fields from the reference object should be obtained from the new fetch group. Consider the Product and Category classes which are mapped to the corresponding Northwind table. A product object has reference to a category. If you want to execute the following statement:

C# Copy Code
scope.FetchPlan.Clear();
scope.FetchPlan.Add("ProductFetchGroup");
var result = scope.Extent<Product>();
foreach (Product product in result)
{
               
string categoryName = product.Category != null ? product.Category.CategoryName : string.Empty;
               Console.WriteLine(
"{0}\t{1}\t{2}", product.ProductID, categoryName, product.ProductName);
}

the ProductFetchGroup should include the Product.productId, Product.productName and Category.categoryName fields, otherwise additional calls to the database will be made.

 

Using FetchPlans with LINQ Queries

All Customer records could be retrieved from the database orderedby their Country field by executing the following LINQ query which would also take advantage of the already specified "Customers" fetch group:

C# Copy Code
scope.FetchPlan.Add("Customers");
var customers = from c
in scope.Extent<Customer>()
               orderby c.Country
select c;
VB.NET Copy Code
scope.FetchPlan.Add("Customers")
Dim customers = From c In scope.Extent(Of Customer)() _
                Order By c.Country _
                Select c

The query above will fetch only the fields specified inside the Customers FetchGroup. In case of using a field which is not part of the used FetchGroups inside the where or the order by clauses, the lazy-loading mechanism will be triggered and all the data available for this persistent object will be loaded from the database. You could apply additional fetch groups like SelectFetchGroup, OrderByFetchGroup, WhereFetchGroup on the fields which will be used for the corresponding operations inside LINQ queries:

C# Copy Code

[FetchField("WhereFetchGroup")]
[FetchField("OrderByFetchGroup")]
private string city;
VB.NET Copy Code

<FetchField("WhereFetchGroup"), FetchField("OrderByFetchGroup")> _
Private city As String

Now the city field can be used inside the where and order by clauses without triggering the lazy-loading mechanism:

C# Copy Code
scope.FetchPlan.Add("Customers");
scope.FetchPlan.Add(
"WhereFetchGroup ");
scope.FetchPlan.Add(
"OrderByFetchGroup ");
 
var customers = from c
in scope.Extent<Customer>()
               orderby c.Country
               select c;  
VB.NET Copy Code
scope.FetchPlan.Add("Customers")
scope.FetchPlan.Add("WhereFetchGroup ")
scope.FetchPlan.Add("OrderByFetchGroup ")
Dim customers = From c In scope.Extent(Of Customer)() _
                Order By c.Country _
                Select c

See Also