Living in the Tech Avalanche Generation

A practitioner’s introspective on technology
Archive for July 15th, 2008

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

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