Living in the Tech Avalanche Generation

A practitioner’s introspective on technology

LINQ To SQL, Dynamic Querying & Fetching Strategies (cont)

I posted recently on using the Specification Pattern and utilizing the generic Expression<> and Func<> to dynamically change the criteria of SQL queries generated by the LINQ To SQL implementation. I promised to come back with an approach on enabling Eager Loading by implementing a Fetching strategy, that can be used with my Repository. Here’s the Fetching Strategy code (most of it).

   1:  public interface IFetchingStrategy
   2:  {
   3:      DataLoadOptions LoadOptions { get; }
   4:  }
   5:   
   6:  public interface IFetchingStrategy<TRole> : IFetchingStrategy
   7:  {
   8:   
   9:  }
  10:   
  11:  public interface ICustomerLoyaltyDiscount
  12:  {
  13:   
  14:  }
  15:   
  16:  public class CustomerLoyaltyDiscountFetchingStrategy : 
  17:                   IFetchingStrategy<ICustomerLoyaltyDiscount>
  18:  {
  19:      private readonly DataLoadOptions _loadOptions;
  20:   
  21:      public DataLoadOptions LoadOptions
  22:      {
  23:          get { return _loadOptions; }
  24:      }
  25:   
  26:      public CustomerLoyaltyDiscountFetchingStrategy()
  27:      {
  28:          _loadOptions = new DataLoadOptions();
  29:          _loadOptions.LoadWith<Customer>(c => c.Orders);
  30:          _loadOptions.LoadWith<Order>(o => o.OrderLines);
  31:      }
  32:  }

Most of the code above is self explanatory except perhaps for the interface ICustomerLoyaltyDiscount on line 11. This interface is used to describe a role in my repository so I can dynamically lookup Fetching Strategies that take that role as a generic parameter and use them to fetch data.

   1:  internal static void SimpleRepositoryDynamicFetching()
   2:  {
   3:      Specification<poco.Customer> simonsCoSpec =
   4:          new Specification<poco.Customer>
   5:              (c => c.Country == "Germany");
   6:   
   7:      DataContext ctx = GetContext();
   8:   
   9:      Repository<poco.Customer> customerRepository =
  10:          new Repository<poco.Customer>(ctx);
  11:   
  12:      var custs = customerRepository.
  13:               All<ext.ICustomerLoyaltyDiscount>(simonsCoSpec);
  14:   
  15:      foreach (var cust in custs)
  16:      {
  17:          Console.WriteLine("The Name of the Customer " +
  18:                   "from Germany is {0}",
  19:                   cust.CompanyName);
  20:          foreach (var order in cust.Orders)
  21:          {
  22:              Console.WriteLine("\tOrder Number {0}", 
  23:                               order.OrderID);
  24:              foreach (var orderLine in order.OrderLines)
  25:              {
  26:                  Console.WriteLine("\t\tProduct ID {0} " +
  27:                      "Amount {1}",
  28:                      orderLine.ProductID, 
  29:                      (orderLine.Quantity * 
  30:                        orderLine.UnitPrice));
  31:              }
  32:          }
  33:      }
  34:  }

As you can see from the code above, when I call the Repository ALL method (as shown below), I use the overload that takes a generic parameter, indicating to the repository to look for a Fetching Strategy that also has this generic argument defined as its role.

   1:  public IList<T> All<TRole>(ISpecification<T> spec)
   2:  {
   3:      using (_context)
   4:      {
   5:          ext.IFetchingStrategy<TRole> strategy = 
   6:              DynamicFetchingStrategyLoad<TRole>();
   7:          _context.LoadOptions = strategy.LoadOptions;
   8:          return GetTable().Where(spec.EvalPredicate).
   9:                            ToList<T>();
  10:      }
  11:  }

The next time I post on this subject I will include the entire code, repository, specifications and fetching strategies.

Share/Save/Bookmark

4 Comments so far

  1. ejr September 5th, 2008 12:55 am

    how do you handle the issue that a datacontext cannot have load options overwritten once it executes a query? do you completely trash the existing context with a new one? this will have some nasty implications with persistance…

    [Reply]

  2. Simon Segal September 5th, 2008 10:30 am

    Objects are being re-attached in subsequent calls where this is a truly disconnected environment (Services & Web Applications). Also the POCO Domain Model objects are being used in the context of applications that implement an MVP framework so the DataContext is not being relied on to manage application state.

    [Reply]

  3. [...] the LINQ To SQL OR/M along with Specifications (for dynamic querying and equality testing) and Fetching Strategies (providing flexible load options to suit the eager or lazy load requirements). What was missing in [...]

  4. [...] This test demonstrates the ability of Specifications to query in memory entities for equality based on lambda expressions. I have talked about this before in the posts on the LINQ To SQL version so for more discussion about Specifications I suggest you look here. [...]

Leave a reply

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia