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