Archive for the 'Design Patterns' Category
LINQ To XML and the Specification Pattern - [In a static world]
I have documented quite extensively on how to use the Specification Pattern and in particular how that can work with a variety of LINQ flavours. The pattern has proven useful in matching objects based on a computation that seeks to test equality and when turned slightly on it’s head a little, it can provide dynamic querying capability to the current Microsoft group of ORM products, namely LINQ To SQL and the Entity Framework. You can check out most of the series on this topic from here. In more recent times I looked at how to use the same pattern with IronRuby which whilst very satisfying for the author, it currently lacks the ability to produce expressions that either ORM products are capable of utilising.
So, for the moment I want to go back again to the Specification pattern and explore it’s use specifically in the world of C# and it’s statically typed sibling languages. The Specification that I currently use is based primarily around our ability to push around Expression<Func<T>> and Func<T> as delegates that can be used as arguments to the extension methods in a given LINQ implementation. Therefore, LINQ to XML should be no exception. Given that the class at the centre of all this ( Specification<T> ) matches objects that satisfy a boolean condition that is asserted using the generic T argument, we are able to specify a function to pass to any extension method implemented by the LINQ To XML provider, that takes a generic as it’s input parameter and returns a boolean. A quick reminder of the Specification classes interface:
public interface ISpecification<T> { Expression<Func<T, bool>> EvalPredicate { get; } Func<T, bool> EvalFunc { get; } bool Matches(T entity); }
Here is a simple example of filtering a query over XML data by supplying a predicate in the form of a specification.
public void employees_from_uk() { var all_employees_on_file = XDocument.Load(@"..\..\XML\Employees.xml").Descendants(); Specification<XElement> aus_emp_spec = new Specification<XElement> (x => x.Attribute("Country").Value == "Australia"); var aus_employees = from e in all_employees_on_file.Descendants() .Where(aus_emp_spec.EvalFunc) select e; aus_employees.ToList().ForEach(x => { Console.WriteLine(x.ToString()); }); }
And now a more complex specification that uses the AND operator to create a combined set of conditions to be satisfied in a .Where extension method.
public void employees_from_uk_that_are_ceo() { var all_employees_on_file = XDocument.Load(@"..\..\XML\Employees.xml").Descendants(); var aus_emp_spec = new Specification<XElement> (x => x.Attribute("Country").Value == "UK"); var ceo_emp_spec = new Specification<XElement> (x => x.Attribute("Title").Value == "CEO"); var compound_spec = aus_emp_spec & ceo_emp_spec; var aus_employees = from e in all_employees_on_file.Descendants() .Where(compound_spec.EvalFunc) select e; aus_employees.ToList().ForEach(x => { Console.WriteLine(x.ToString()); }); }
More than just a ‘Where’ predicate?
Your probably noticing that we are always applying our specifications to the “where” method. As I mentioned, a Specification in it’s current incarnation can only be applied to extension methods that take a function that accepts a generic argument as an input parameter and returns a boolean, therefore there are some other methods that can be specified. Here is example of using the .SkipWhile() extension method.
public void skip_while_employees_from_usa_then_return_the_rest_regardless() { var all_employees_on_file = XDocument.Load(@"..\..\XML\Employees.xml").Descendants(); var usa_empoyee_spec = new Specification<XElement> (x => x.Attribute("Country").Value == "USA"); var usa_emps = from e in all_employees_on_file.Descendants() .SkipWhile(usa_empoyee_spec.EvalFunc) select e; usa_emps.ToList().ForEach(x => { Console.WriteLine("Skipping from the USA : " + x.ToString()); }); }
The final example combines data from two XML sources, each one requiring it’s own specification, where the LINQ query will bring the disparate data together.
public void customer_joined_with_customer_representative() { var cust_rep_spec = new Specification<XElement>(x => x.Name == "CustomerRep"); var emp_id_spec = new Specification<XAttribute>(x => x.Name == "EmployeeID"); var all_employees_on_file = XDocument.Load(@"..\..\XML\Employees.xml").Descendants().Attributes(); var all_customers_on_file = XDocument.Load(@"..\..\XML\Customers.xml").Root.Descendants().Elements(); var customer_with_rep = from c in all_customers_on_file.Where(cust_rep_spec.EvalFunc) from e in all_employees_on_file.Where(emp_id_spec.EvalFunc) where c.Value == e.Value select new { c = c.Parent.Element("FirstName").Value + " " + c.Parent.Element("LastName").Value, e = e.Value }; customer_with_rep.ToList().ForEach(x => { Console.WriteLine( string.Format("Customer : {0} is represented by Rep Number {1}", x.c, x.e)); }); }
Employee.xml File
<?xml version="1.0" encoding="utf-8" ?> <Employees> <Employee EmployeeID="1" FirstName="Nancy" LastName="Davolio" Title="Sales Representative" HireDate="1992-05-01T00:00:00" Country="USA" Extension="5467" /> <Employee EmployeeID="2" FirstName="Andrew" LastName="Fuller" Title="Vice President, Sales" HireDate="1992-08-14T00:00:00" Country="AUSTRALIA" Extension="3457" /> <Employee EmployeeID="3" FirstName="Janet" LastName="Leverling" Title="Sales Representative" HireDate="1992-04-01T00:00:00" Country="USA" Extension="3355" /> <Employee EmployeeID="4" FirstName="Margaret" LastName="Peacock" Title="Sales Representative" HireDate="1993-05-03T00:00:00" Country="AUSTRALIA" Extension="5176" /> <Employee EmployeeID="5" FirstName="Steven" LastName="Buchanan" Title="Sales Manager" HireDate="1993-10-17T00:00:00" Country="UK" Extension="3453" /> <Employee EmployeeID="6" FirstName="Michael" LastName="Suyama" Title="Sales Representative" HireDate="1993-10-17T00:00:00" Country="UK" Extension="428" /> <Employee EmployeeID="7" FirstName="Robert" LastName="King" Title="CEO" HireDate="1994-01-02T00:00:00" Country="UK" Extension="465" /> <Employee EmployeeID="8" FirstName="Laura" LastName="Callahan" Title="Inside Sales Coordinator" HireDate="1994-03-05T00:00:00" Country="USA" Extension="2344" /> <Employee EmployeeID="9" FirstName="Anne" LastName="Dodsworth" Title="Sales Representative" HireDate="1994-11-15T00:00:00" Country="UK" Extension="452" /> </Employees>
Customers.xml File
<?xml version="1.0" encoding="utf-8" ?> <Customers> <Customer> <FirstName>Simon</FirstName> <LastName>Segal</LastName> <JoinDate>19-10-2008</JoinDate> <Country>Australia</Country> <Email>simon.segal@techavalanche.com</Email> <MobilePhone>0405987367</MobilePhone> <CustomerRep>2</CustomerRep> </Customer> <Customer> <FirstName>Bob</FirstName> <LastName>Jones</LastName> <JoinDate>23-10-2008</JoinDate> <Country>Germany</Country> <Email>bob.j@bundes.com</Email> <MobilePhone>8983478347</MobilePhone> <CustomerRep>1</CustomerRep> </Customer> <Customer> <FirstName>Clair</FirstName> <LastName>Humgola</LastName> <JoinDate>10-10-2008</JoinDate> <Country>Australia</Country> <Email>chumg@telstra.com.au</Email> <MobilePhone>0458193487</MobilePhone> <CustomerRep>4</CustomerRep> </Customer> <Customer> <FirstName>Milton</FirstName> <LastName>Nomik</LastName> <JoinDate>20-12-2008</JoinDate> <Country>Australia</Country> <Email>milt.n@techavalanche.com</Email> <MobilePhone>09072625717</MobilePhone> <CustomerRep>6</CustomerRep> </Customer> </Customers>
On a final note: I am going to have a go shortly at putting together some variations of the Specification<T> class to allow for a more complete use with LINQ in General, remembering that the initial requirement was based around testing objects for equality and then creating a more manageable and malleable system of creating dynamic queries in LINQ To SQL and the Entity Framework. The “new” Specification class will need to support more than the just Func<T, bool> and should prove to be in interesting exercise.
Full code download for this post can be found here.
No commentsSpecification Pattern in IronRuby
The Specification Pattern is one that I admire and have used often and most recently to good effect with both LINQ To SQL and the Entity Framework. This little gem of a pattern came in very useful with both ORM’s to enable dynamic queries built off Expressions or to be precise Expression<Func<T>>. If you want to know more about these implementations, then look here.
More recently in my travels down the polyglot road, I wanted to give the pattern a run with IronRuby. And boy I wasn’t disappointed. Getting a specification together in IronRuby was noticeably quicker and easier however please note that it lacks the happy ORM by-product as detailed above. Best to dive straight in to the code:
class Specification def initialize(expression) @expression = expression end def Matches(match_object) @expression.call(match_object) end end
And that’s all folks. Compared to C# it’s certainly less code and I can’t help but enjoy it’s brevity. Let’s add some spice with a user defined class to test with specifications.
class Customer def Name @name end def Age @age end def initialize(name, age) @name = name @age = age end end
And now let’s test this baby out:
#pass some code to test if a given number is less than 200 spec = Specification.new(lambda {|num| num < 200}) num_to_spec_on = 123 number_is_less_than_two_hundred = spec.Matches(num_to_spec_on) puts "It is #{number_is_less_than_two_hundred} " + "that #{num_to_spec_on} is less than 200" #use a user defined class to test with a specification cust = Customer.new("Simon Segal", 35) spec = Specification.new(lambda {|cust| cust.Name == "Simon Segal"}) customer_name_is_simon_segal = spec.Matches(cust) puts "It is #{customer_name_is_simon_segal} that the customer is Simon Segal" #combining lambdas into more complex specifications l1 = lambda {|num| num > 1} l2 = lambda {|num| num < 100} l3 = l1 && l2 num = 54 spec = Specification.new(l3) number_between_1_and_100 = spec.Matches(54) puts "#{number_between_1_and_100} #{num} is between 1 and 100"
The Result’s
Looking at this code, you will see that we have dialled up an explicit arithmetic specification to test a given numbers value is less than 200 followed by an evaluation of a Customer object, testing if it’s name is equal to my very own moniker. Finally, an example of combining lambdas to produce more complex specifications. Here are the results (I am still using Ruby In Steel, which I prefer to the other options and it’s still free).
Download my learning IronRuby Visual Studio Project and code
No commentsEntity Framework, Repositories, Specifications and Fetching Strategies Part 8.0
This thread of posts is becoming unwieldy in it’s naming convention and difficult to follow if you have come to it very recently. To help rectify or rather improve that situation I have created this linking post which has taken the physical posts that make up the series and logically renamed them here. I will follow in the next couple of days with Part 9.0 which will address strongly typed FetchingIntentions using lambda expressions (at the suggestion of K. Scott Allen). Part 10 will cover dependency injecting the Fetching Strategies by expressing intent via roles (specifying an interface).
Entity Framework, Repositories, Specifications and Fetching Strategies Part 1.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 2.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 3.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 4.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 5.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 6.0
Entity Framework, Repositories, Specifications and Fetching Strategies Part 7.0
1 comment







