Living in the Tech Avalanche Generation

A practitioners 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

3 comments

LINQ to SQL, the Specification Pattern and Dynamic Queries

A while back Udi posted on Fetching Strategies that he implemented with NHibernate. I have just finished working on an implementation of the Specification Pattern that will work with LINQ (to objects) using Lambdas to provide the test logic and in the case of LINQ to SQL using the same testing predicates as search predicates when querying the database.

   1:  public static void SpecForLambdaWithDatabase()
   2:  {
   3:      Specification<Customer> coNameSpec =
   4:          new Specification<Customer>
   5:              (c => c.CompanyName == “Blauer See Delikatessen”);
   6:  
   7:      NorthwindDataContext ctx = new NorthwindDataContext();
   8:  
   9:      //TODO: Turn this into a fetching strategy that
  10:      //can be loaded when a Repository method is called
  11:      //using a role. Dependancy Injection will be useful 
  12:      //in allowing us slot in different fetching strategies 
  13:      //over time if required.
  14:      DataLoadOptions options = new DataLoadOptions();
  15:      options.LoadWith<Customer>(c => c.Orders);
  16:      options.LoadWith<Order>(o => o.OrderLines);
  17:      ctx.LoadOptions = options;
  18:  
  19:      //Note: the specification passes it’s EvalPredicate
  20:      //as a Func<T,bool> argument to the ‘Where’
  21:      //extension method
  22:      var exp = from c in ctx.Customers
  23:                .Where<Customer>(coNameSpec.EvalPredicate)
  24:                select c;
  25:  
  26:      foreach(var c in exp)
  27:      {
  28:          Console.WriteLine(“The Customer ID ‘{0}’ “ +
  29:              “AND NAME ‘{1}’”,
  30:              c.CustomerID, c.CompanyName);
  31:      }
  32:  }

My next goal is to enable the eager and lazy loading in these scenarios dealt with by using something similar to Fetching Strategies and have the Repository load them using dependency injection which will enable me to plug in the correct fetching strategy at will.

Shortly I will post some code that demonstrates all this with a Repository and not the standard .DBML file, DataContext way of doing things as per above.

Share/Save/Bookmark

1 comment

Lambdas, VB 9.0, C# and the polyglot kid.

I used to be a VB 4, 5, and 6 hacker back in the day and I will confess that when I first went down the .NET path I chose VB.Net as the language vehicle of learning. Shortly after developing my first .NET application I made the immediate decision to switch languages and decided to use C# as my first choice. The reasons were simple: I found the language more compact, more elegant to read and the resources for .NET in the early days seemed to far more abundant in C#.

From time to time I do choose to implement a component or two using VB.Net; this was simply to stay in touch with the language. Most recently I found this exercise a bit harder to stomach when I had to write some lambda’s in VB 9.0.

Dim dlo As DataLoadOptions = New DataLoadOptions()
dlo.LoadWith(Of Customer)(Function(c As Customer) c.Orders)
db.LoadOptions = dlo

Any more brackets and keywords and I would be ready to pick up my guitar to make a living. This code fsharplogo had me really thinking that I was glad to that my “checking in with VB.Net” was an occasional practice, in fact it got me to thinking that perhaps it was becoming a bit of waste of time and that the practice should be more about checking out a new language paradigm rather than another empirical statically typed language for the same platform. Enter the polyglot programmer debate. And so, the outcome is that I have made the determination that rubylogo my spare “language time” will go into Ruby and F# having assigned some value to the idea that both functional and dynamic languages should be explored NOW and in some depth. Functional programming has caught my imagination quite a bit of late and I can see some real application in the document management domain where we constantly find ourselves dealing with large recursive trees of data that are immutable.

Share/Save/Bookmark

No comments

Data Programmability Advisory Council announced!

For those of you who are struggling with the idea or even still the practice of applying Domain Driven Design and using Microsoft Technology in the process, there is some very good news (potentially). Danny Simmons (noted Microsoft ADO.Net / Entity Framework team member) announced the advisory council for blue_data Data Programmability. This council is a who’s who of the DDD world and so it should provide some great real world commercial & practical requirements to the team in driving forward the next versions of products such as LINQ to SQL and the Entity Framework and making these tools more effortlessly support the practice of DDD. Now having said all that, you can get some part of the way their now and Ian Cooper has produced some good work in that area. I must admit that I have avoided taking a really serious look at the EF because persistence ignorance isn’t possible in the first release, however I am starting to feel a bit more positive about about subsequent releases given this latest announcement and Danny Simmons previous announcements that PI supporting infrastructure would be baked into V 1.0 making it’s inclusion in subsequent versions more likely without breaking changes being required.

Share/Save/Bookmark

1 comment

Pay attention to where you use your LINQ Queries

Firstly let me say that I love LINQ. However like any technology stack there are always some gotcha’s that you need to watch out for. Deferred execution is one of LINQ’s great features, however if your not thinking clearly when you use LINQ you could be writing some really poorly performing code.

Consider the following code:

[Test]
public void AbstractFactoryAssertions()
{
     ////mock the factory
     var mock = new Mock<Soccer>();
     //setup a shape
     BallShape shape = BallShape.Round;
     BallType style = new BallType(shape, “Synthetic Fibres”);
     //assert correct state
     Assert.AreEqual(mock.Object.GetBallType().Style.
                     ExternalMaterial, “Synthetic Fibres”);
     Assert.AreEqual(mock.Object.GetBallType().Style.Shape, shape);
     Assert.IsTrue(mock.Object.IsPlayedInternationally);

     //***********************
     //THIS IS THE SMELLY CODE
     Assert.AreEqual(mock.Object.ToString().“Proxy”),
                    mock.Object.ToString().Length -
                    “Proxy”)),
                   “Australia England France Poland” +
                   “UnitedStates all play Soccer”);
                   Assert.IsTrue(mock.Object.GetType().BaseType ==
                   typeof(Soccer));
     //END OF THE SMELLY CODE
     //**********************
}

The smelly code above (see code comments), force three calls to the ToString() method of the Soccer class and this method is defined in the Abstract Factory class of FootballCode, which the Soccer class inherits from. It is the code in the ToString() method of FootballCode base class where we strike problems.

public override string ToString()
{
    var exp = from c in PlayedIn
              select c;
    StringBuilder _tostring = new StringBuilder();
    string myname = this.GetType().Name;
    foreach (Country c in exp)
    {
        _tostring.Append(c.GetType().Name + “|”);
    }
    return _tostring.ToString().Replace(‘|’, ‘ ‘) +
                “all play “ + myname;
}

Three calls to the ToString() method in our test will force the LINQ query to execute three times when we only needed to do so once. It’s an obvious mistake but you need to make sure that wherever you have code that will execute a LINQ query, you remain alert as to how you use or call on it. Lets fix the offending code:

//********************************************
//            Fixed Smelly Code

string soccerToString = mock.Object.ToString();
int idxProxy = soccerToString.LastIndexOf(“Proxy”);
int soccerLength = soccerToString.Length;
Assert.AreEqual(mock.Object.ToString().
                Remove(idxProxy, soccerLength - idxProxy),
                “Australia England France Poland” +
                “UnitedStates all play Soccer”);

//            Fixed Smelly Code
//********************************************

By averting the repeated calls to the ToString() method we bypass the redundant execution of the LINQ query. Actually this is a pretty obvious thing to avoid, but developers need to be vigilant as they TDD there way through the design of the object or domain models. For example, I actually should have refactored the code above in the ToString() method and probably moved it into my constructor and stored the result in a private member and continually referenced it’s value from the ToString() method, making the entire process of getting the data static by nature post object creation.

Another thing to pay attention to is awareness of how deferred execution works and staying clear of nested filtering and setting parameters in variables at the correct juncture. For example if we take the following method:

public void ExampleOfLinqBehaviour()
{
    List<Country> engspeakCountries = new List<Country>();

    string _name = “UnitedStates”;

    var query = from c in PlayedIn
                where c.GetType().Name == _name
                select c;

    //the query will use this as
    //the parameter to the where
    //clause and NOT the value
    //of UnitedStates
    _name = “Australia”;

    //query gets executed here in the 
    //foreach loop and therefore the
    //_name parameter is only used once
    //in the case where its value is
    //equal to Austral and NOT UnitedStates.
    foreach (Country c in query)
    {
        engspeakCountries.Add(c);
    }

    var queryFilter = from c in query
                      where c.Region == “Asia Pacific”
                      select c;

    //this will force both linq queries to
    //execute like nested loops. The first query
    //should already probably have executed rather
    //than executing a second time redundantly
    foreach (Country c in queryFilter)
    {
        Console.WriteLine(c.Region);
    }

    //sometimes you will improve performance by
    //forcing the LINQ query to execute
    var queryForced = (from c in PlayedIn
                where c.GetType().Name == _name
                select c).ToList();

    //iterate the list once only
    queryForced.ForEach(c => Console.WriteLine(c.Region));
}

The mistake above lies in the intention to query with a ‘where’ filter that matches on the initial value of the “UnitedStates”, which is subsequently overwritten prematurely with the value of ‘Australia’ and due to the nature of deferred executing, the query will not execute until the first foreach() statement is executed.

The Debugger & Tracing LINQ To SQL

A final cautionary note: if your tracing SQL queries that are being executed by LINQ To SQL and you use the debugger Linq Debuggerto expand the results view before a query has executed, it will in fact force the query to execute, producing the harvested results and by sending the appropriate TSQL command to the Server.

Share/Save/Bookmark

No comments

Next Page »