<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://bloggingabout.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Dries Marckmann : specification, C#</title><link>http://bloggingabout.net/blogs/dries/archive/tags/specification/C_2300_/default.aspx</link><description>Tags: specification, C#</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Specification Pattern Continued</title><link>http://bloggingabout.net/blogs/dries/archive/2011/09/29/specification-pattern-continued.aspx</link><pubDate>Thu, 29 Sep 2011 04:35:00 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:575724</guid><dc:creator>Dries Marckmann</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://bloggingabout.net/blogs/dries/rsscomments.aspx?PostID=575724</wfw:commentRss><comments>http://bloggingabout.net/blogs/dries/archive/2011/09/29/specification-pattern-continued.aspx#comments</comments><description>&lt;p&gt;&lt;sub&gt;&lt;/sub&gt;&lt;sub&gt;&lt;/sub&gt;In a previous &lt;a href="http://bloggingabout.net/blogs/dries/archive/2010/11/30/specification-pattern-implementation.aspx" target="_blank"&gt;post&lt;/a&gt;, I talked about the specification pattern. In the last sentence I promised you to keep you posted on the next version of the implementation. I still owe you guys that result. So without further ado: &lt;/p&gt;  &lt;p&gt;Download it &lt;a href="http://bloggingabout.net/media/p/575700.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The implementation itself is pretty straightforward. The class has a protected property Predicate that takes in a Lambda expression that results in a boolean ( a predicate). It is protected so that you have to set the predicate in the derived class.&lt;/p&gt;     &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:&amp;#39;Courier New&amp;#39;, courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;&lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;/// Use the Specification to make some complex (business) logic explicit. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;/// &amp;lt;typeparam name=&amp;quot;TEntity&amp;quot;&amp;gt;The Type of entity that is the subject of the specification&amp;lt;/typeparam&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;abstract&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Specification&amp;lt;TEntity&amp;gt;&lt;br /&gt;{&lt;br /&gt;     &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; Func&amp;lt;TEntity, &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&amp;gt; evalCompiled;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; Expression&amp;lt;Func&amp;lt;TEntity, &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; evalExpression;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; Expression&amp;lt;Func&amp;lt;TEntity, &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; Predicate&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; evalExpression;&lt;br /&gt;        }&lt;br /&gt;        set&lt;br /&gt;        {&lt;br /&gt;            evalExpression = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;&lt;br /&gt;            evalCompiled = evalExpression.Compile();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// Use this method to evaluate the predicate for a single item.&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;param name=&amp;quot;item&amp;quot;&amp;gt;The item to examine&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;returns&amp;gt;A boolean.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; IsSatisfiedBy(TEntity item)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; evalCompiled(item);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// Use this method to filter IQueryables using the Predicate &lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;param name=&amp;quot;candidates&amp;quot;&amp;gt;The IQueryable that needs filtering&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;returns&amp;gt;An IQueryable that has the added filter&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IQueryable&amp;lt;TEntity&amp;gt; SatisfyingElementsFrom(IQueryable&amp;lt;TEntity&amp;gt; candidates)&lt;br /&gt;    {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; candidates.Where(evalExpression);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;

&lt;p&gt;The usage is simple. &lt;/p&gt;

&lt;p&gt;Suppose that there is a business rule that big orders need approval by a manager. Big orders are orders above a 1000 euros. There are 2 cases when we need to know whether an order is a big order. First, when the order is created so that we can send a request for approval to the manager and second in a managers app that shows all the big orders.&lt;/p&gt;

&lt;p&gt;The class IsBigOrderSpecification is a business rule made explicit. This rule could be throughout your system. Here’s what it looks like:&lt;/p&gt;


  &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:&amp;#39;Courier New&amp;#39;, courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; IsBigOrderSpecification : Specification&amp;lt;SalesOrderDetail&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IsBigOrderSpecification()&lt;br /&gt;    {&lt;br /&gt;        Predicate = (o =&amp;gt; o.LineTotal &amp;gt;= 1000);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;

&lt;p&gt;When a new order is created we can now use this specification to enforce the business rule.&lt;/p&gt;


  &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:&amp;#39;Courier New&amp;#39;, courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;SalesOrderDetail orderLine = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SalesOrderDetail();&lt;br /&gt;orderLine.LineTotal = 999;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; isBigOrderLine = isBigOrderLineSpec.IsSatisfiedBy(orderLine);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (isBigOrderLine)&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;LineTotal {0} means this is a big orderline.&amp;quot;&lt;/span&gt;, orderLine.LineTotal);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;LineTotal {0} means this is a not big orderline.&amp;quot;&lt;/span&gt;, orderLine.LineTotal);&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;

&lt;p&gt;Yet the same specification can be used when querying for these big orders in the system. Because it works on IQueryable&amp;lt;SalesOrderDetail&amp;gt; we get all the advantages of deferred execution. &lt;/p&gt;


  &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:&amp;#39;Courier New&amp;#39;, courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;AdventureWorksEntities db = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AdventureWorksEntities();&lt;br /&gt;&lt;br /&gt;var query = from so &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; db.SalesOrderDetails&lt;br /&gt;                        select so;&lt;br /&gt;&lt;br /&gt;var bigOrderLines = isBigOrderLineSpec.SatisfyingElementsFrom(query);&lt;br /&gt;&lt;br /&gt;Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;{0} big OrderLines in database&amp;quot;&lt;/span&gt;, bigOrderLines.Count());&lt;/pre&gt;

  &lt;br /&gt;

&lt;h2&gt;&amp;#160;&lt;/h2&gt;

&lt;h2&gt;Composite specification&lt;/h2&gt;

&lt;p&gt;In the solution you can also find the code to create composite specifications. Composite specifications are specifications that have been combined. What if we changed the business rule (the manager is getting to busy) to state that only big orders from sales people that have little experience have to be approved. Little experience has been qualified at working at the company less than 2 years. You probably get an IsExperiencedSalesPersonSpecification. &lt;/p&gt;

&lt;p&gt;We are now able to combine the 2 specifications as follows: &lt;/p&gt;


  &lt;pre style="border-bottom-style:none;text-align:left;padding-bottom:0px;line-height:12pt;background-color:#f4f4f4;margin:0em;border-left-style:none;padding-left:0px;width:100%;padding-right:0px;font-family:&amp;#39;Courier New&amp;#39;, courier, monospace;direction:ltr;border-top-style:none;color:black;border-right-style:none;font-size:8pt;overflow:visible;padding-top:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; needsApproval = isBigOrderLineSpec.And(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IsExperiencedSalesPersonSpecification().Not()).IsSatisfiedBy(orderLine);&lt;/pre&gt;

  &lt;br /&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;My opinion is that this specification pattern is quite powerful in specifying and enforcing business rules in a distributed system.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://bloggingabout.net/aggbug.aspx?PostID=575724" width="1" height="1"&gt;</description><category domain="http://bloggingabout.net/blogs/dries/archive/tags/Linq/default.aspx">Linq</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/IQueryable/default.aspx">IQueryable</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/pattern/default.aspx">pattern</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/specification/default.aspx">specification</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/DDD/default.aspx">DDD</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/.Net/default.aspx">.Net</category><category domain="http://bloggingabout.net/blogs/dries/archive/tags/C_2300_/default.aspx">C#</category></item></channel></rss>