LinqConnect Documentation
In This Topic
    Lazy Loading
    In This Topic
    Lazy Loading
    LinqConnect Documentation
    Lazy Loading
    [email protected]

    Lazy loading is the pattern that is used to defer initialization of an object until this object is really needed by application. It is an opposite to the eager loading pattern, which supposes the immediate object initialization. In LinqConnect, lazy loading can be used for relationships and 'plain' entity fields.

    Relationships

    Lazy loading is enabled by default for entity relationships in LinqConnect. Now we describe how it works.

    Note:
    The lazy loading functionality is only available for references that have navigation properties of the EntitySet/EntityRef types. For IList and 'plain entity' navigation properties of POCO classes, only eager loading can be used.

    Suppose a table is linked to another one (for example, 'Order Detail' and 'Order' from the CRM Demo sample database) via a foreign key. The corresponding entity classes should have a one-to-many association; i.e., we can think that each Order instance has a collection (possibly empty) of OrderDetail objects. To simplify accessing this collection, the code-generation templates create the OrderDetails property in the Order class (and the Order property in the OrderDetail class to navigate in the reverse direction). Such properties are called navigation properties.

    Though it is convenient to get the collection of related objects via a property, you probably don't want to fetch and materialize all the related details each time you get the information about a particular order (specifically, this would cause materializing entities related to these details, and so on). Thus, the related entities are not fetched until you explicitly address to the corresponding collection:


    C#csharpCopy Code
    var orderQuery = from order in context.Orders
                     where order.ShipDate.Value.Year == 2007
                     select order;
    // At this point, order details are not retrieved.
    var orders2007 = orderQuery.ToList();
    
    foreach (Order order in orders2007)
    {
        double sum = 0;
        // And now LinqConnect do get the details from the database.
        foreach (OrderDetail detail in order.OrderDetails)
            sum += detail.Price.GetValueOrDefault();
        Console.WriteLine("Order {0}, total cost: {1}$.", order.OrderID, sum);
    }
    
    Visual BasicCopy Code
    Dim orderQuery = From order In context.Orders _
                     Where order.ShipDate.Value.Year = 2007 _
                     Select order
    ' At this point, order details are not retrieved.
    Dim orders2007 = orderQuery.ToList()
    
    For Each order As Order In orders2007
        Dim sum As Double = 0
        ' And now LinqConnect do get the details from the database.
        For Each detail As Orderdetail In order.Orderdetails
            sum += detail.Price.GetValueOrDefault()
        Next
        Console.WriteLine("Order {0}, total cost: {1}$.", order.OrderID, sum)
    Next

    The same is applicable to the navigation properties used to access a single entity instead of a collection (e.g., the Order property of the OrderDetail class): until you directly refer to such a property, no query is performed to get the order from the database.

    In some scenarios, however, you do want to get all related entities when fetching the 'main' one. For the details on performing such a task, refer to the Eager Loading topic in this section.

    Simple Fields

    By default, all entity fields are loaded eagerly, since this suits most common situations. However, in some cases you may want to change this behaviour. For example, when only a part of columns is bound to a grid, there is no point to fetch the other part for the whole displayed record set. Or, if a table has a large binary column (e.g., Oracle BLOB or SQL Server 'image'), one has to fetch few megabytes of binary data for just doing several changes to the columns of 'simple' types if the delay loading is not enabled for this column.

    To specify that a column should be delay loaded, define this field as Devart.Data.Linq.Link<field type> Or, if using Entity Developer, set the 'Delay Loaded' property of the corresponding entity member to 'true' in your model, and Entity Developer will generate the code on its own.

    Note:
    If several columns are marked to be delay loaded, and you refer to one of them in your code, only this particular column is being fetched. If you want to access a set of delay loaded columns simultaneously, consider implementing a Table-Per-Hierarchy inheritance instead.

    Technical details

    For those interested in the implementation details: LinqConnect uses the following wrapper class and structures to provide the lazy loading feature:

    • EntitySet<TEntity> is the wrapper for collection navigation properties (i.e., for 'many' sides of associations). It fetches these entities when being enumerated. For example, here is the definition of the OrderDetails property of the Order class generated for the 'Orders' and 'Order Details' tables of the sample CRM Demo database:


      C#csharpCopy Code
      public partial class Order : INotifyPropertyChanging, INotifyPropertyChanged
      {
          //...
          private EntitySet<Orderdetail> _OrderDetails;
          //...
          public EntitySet<Orderdetail> OrderDetails
          {
              get { return this._OrderDetails; }
              set { this._OrderDetails.Assign(value); }
          }
       
      }
      Visual BasicCopy Code
      Partial Public Class Order
          Implements INotifyPropertyChanging
          Implements INotifyPropertyChanged
          '...
          Private _OrderDetails As EntitySet(Of Orderdetail)
          '...
          Public Property OrderDetails() As EntitySet(Of Orderdetail)
              Get
                  Return Me._OrderDetails
              End Get
              Set(value As EntitySet(Of Orderdetail))
                  Me._OrderDetails.Assign(value)
              End Set
          End Property
      End Class

    • EntityRef<TEntity> is the wrapper used for the 'single object' navigation properties (i.e., for 'one' sides of associations). More precisely, it is the type of the private fields corresponding to the singleton navigation properties; these properties themselves expose entity objects via the Entity property of EntityRef:


      C#csharpCopy Code
      public partial class OrderDetail : INotifyPropertyChanging, INotifyPropertyChanged {
          //...
          private EntityRef<Order> _Order;
          //...
          public Order Order 
          {
              get { return this._Order.Entity; }
              set { /* ... */ }
          }
      }
      Visual BasicCopy Code
      Partial Public Class OrderDetail
          Implements INotifyPropertyChanging
          Implements INotifyPropertyChanged
          '...
          Private _Order As EntityRef(Of Order)
          '...
          Public Property Order() As Order
              Get
                  Return Me._Order.Entity
              End Get
              Set(value As Order)
                  ' ... 
              End Set
          End Property
      End Class

      Thus, the related entity is fetched and materialized when the navigation property is addressed.

    • Devart.Data.Linq.Link wraps 'plain' entity fields being delay loaded. Again, only the private field is wrapped, and the public property exposes the column value via the Link.Value property:


      C#csharpCopy Code
      public partial class Company : INotifyPropertyChanging, INotifyPropertyChanged
      {
          //...
          private Devart.Data.Linq.Link<string> _Fax;
          //...
          public string Fax
          {
              get { return this._Fax.Value; }
              set { /* ... */ }
          }
      }
      Visual BasicCopy Code
      Partial Public Class Company
          Implements INotifyPropertyChanging
          Implements INotifyPropertyChanged
          '...
          Private _Fax As Devart.Data.Linq.Link(Of String)
          '...
          Public Property Fax() As String
              Get
                  Return Me._Fax.Value
              End Get
              Set(value As String)
                  ' ... 
              End Set
          End Property
      End Class