<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7476247</id><updated>2011-11-04T15:31:24.213Z</updated><category term='.Net 2.0'/><category term='DTS'/><category term='Regular Expressions'/><category term='DevOps'/><category term='SQL Server Integration Services'/><category term='Replication'/><category term='SQL Server'/><category term='.Net'/><category term='PowerPivot'/><category term='Visual Studio 2010 Database Projects'/><category term='Geometry'/><category term='Reporting Services 2008'/><category term='Merge Replication'/><category term='Business Intelligence'/><category term='Builds'/><category term='Unit Tests'/><category term='NDepend'/><category term='PowerShell'/><category term='Agile Reporting'/><category term='Web Parts'/><category term='Shareport'/><category term='Data Warehouse'/><category term='Reporting Services 2005'/><category term='SfTS v3'/><category term='SSIS'/><category term='Transaction Replication'/><category term='MDS'/><category term='SfTS'/><category term='Design Patterns'/><category term='ADO.Net'/><category term='SSRS 2000'/><category term='Master Data Services'/><category term='SQL Server 2008'/><category term='.Net 3.0'/><category term='Test Driven Development'/><category term='Build Metrics'/><category term='Web Services'/><category term='SQL Server 2005'/><category term='TFS2010'/><category term='HTTP EndPoints'/><category term='XML'/><category term='Rules Engine'/><category term='SharePoint 2010'/><category term='Team Foundation Server 2010'/><category term='MSBuild'/><category term='Java'/><category term='Change Data Capture'/><category term='TFS2008'/><category term='Team Foundation Server 2008'/><category term='TFSDeployer'/><category term='C#'/><category term='TDD .Net'/><category term='Reporting Services 2000'/><category term='ReSharper'/><category term='SfTS v2'/><category term='Scrum for Team System'/><category term='Agile'/><category term='SSRS 2005'/><category term='Geo Spatial'/><category term='Tools'/><category term='SSRS 2008'/><category term='DBA'/><category term='SQL Server 2008 R2'/><category term='TFS Custom Adapters'/><category term='VSTDB'/><category term='Multithreading'/><category term='CDC'/><category term='Visual Studio 2005 Team Edition for Database Professionals'/><title type='text'>Steven Wright Blog</title><subtitle type='html'>A collection of notes and findings</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>54</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7476247.post-1773283261669082223</id><published>2011-10-17T17:18:00.001+01:00</published><updated>2011-10-17T19:12:28.714+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='Builds'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2010 Database Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2010'/><category scheme='http://www.blogger.com/atom/ns#' term='VSTDB'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='TFSDeployer'/><category scheme='http://www.blogger.com/atom/ns#' term='DevOps'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerShell'/><title type='text'>A Business Intelligence project ALM's</title><content type='html'>&lt;p&gt;&lt;strong&gt;&lt;u&gt;Table of Contents&lt;/u&gt;&lt;/strong&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="889"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="22"&gt;1 &lt;/td&gt; &lt;td valign="top" width="26"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="839"&gt;Introduction. &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22"&gt;2&lt;/td&gt; &lt;td valign="top" width="26"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="839"&gt;Automation process components &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="26"&gt;2.1 &lt;/td&gt; &lt;td valign="top" width="839"&gt;The Build.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22" cellpadding="10"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="26"&gt;2.2&lt;/td&gt; &lt;td valign="top" width="839"&gt;The Deployment script.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22" cellpadding="10"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="26"&gt;2.3&lt;/td&gt; &lt;td valign="top" width="839"&gt;Automated deployment and execution.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22"&gt;3 &lt;/td&gt; &lt;td valign="top" width="26"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="839"&gt;Visual studio tips. &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22" cellpadding="10"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="26"&gt;3.1&lt;/td&gt; &lt;td valign="top" width="839"&gt;Reducing unresolve reference errors.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22" cellpadding="10"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="26"&gt;3.2 &lt;/td&gt; &lt;td valign="top" width="839"&gt;Composite Projects.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="22"&gt;4 &lt;/td&gt; &lt;td valign="top" width="26"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="839"&gt;Resources. &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt; &lt;h4&gt;&lt;a name="Introduction"&gt;1 Introduction&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;As I have mentioned in previous posts I have been working on a data warehouse project. One of my main roles in this project was to work on the build, deployment and development processes. Within this post, I would like to show how I, with help from my colleagues, was able to automate a build, deployment and execute the data warehouse code.&lt;/p&gt; &lt;p&gt;The reason for developing this automation was to try and find problems before we released to user acceptance testing (UAT). Once this automation started running it did capture errors. One error in particular, which would only appeared in release, was missing permissions. As the developers and the testing team all have different elevated rights, so that they can do their jobs, masked the problem ever existed. &lt;/p&gt; &lt;h4&gt;&lt;a name="AutomationProcessComponents"&gt;2 Automation process components&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;&lt;a href="http://lh4.ggpht.com/--gKt5xM4BjI/TpxVROMbTmI/AAAAAAAAAHA/fnNzMbtHq18/s1600-h/Automation16.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Automation - Build" border="0" alt="A child with building blocks" src="http://lh5.ggpht.com/-VUG5U7Llkzo/TpxVRiCisWI/AAAAAAAAAHI/vKI5kUje6Fs/Automation1_thumb4.png?imgmax=800" width="333" height="92"&gt;&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;&lt;a name="TheBuild"&gt;2.1 The Build&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;To develop our data warehouse solution the project used the Microsoft development tools: Team Foundation Server (TFS) 2010 and Visual Studio (VS) 2010 / 2008. TFS 2010 was used as a source control repository and automated build platform (Team build). VS 2010 was used to develop our database code and VS 2008 - Business Intelligence Studio (BIDS) for creating the integration packages and analysis services cubes. &lt;/p&gt; &lt;p&gt;As we were using the above tools I was able to create, using my company's IP, a build that would drop deployable artefacts. This was then wrapped into a TFS build which would be triggered by a number of check-ins. This gave us our continuous build for the project which was helpful to find problems like: incompatible code between team members; incomplete check-ins missing files from the change set.&lt;/p&gt; &lt;p&gt;However, if a build was successful it didn't mean that the build was deployable. An example of this is an unresolved reference warning which shouldn’t have been a warning but an error. This happened to us, one of our builds which we tried, had several unresolved reference warnings, we tried to deploy but failed because a view referenced to a column within a table was invalid.&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-XNhzMWZHlrY/TpxVSFq5qrI/AAAAAAAAAHQ/CLzVjVHDuhQ/s1600-h/Automation26.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Automation - Deployment" border="0" alt="A parachutist" src="http://lh6.ggpht.com/-YnpNaNfEDlA/TpxVSj7Tl5I/AAAAAAAAAHY/UTpRcgswu_E/Automation2_thumb4.png?imgmax=800" width="333" height="92"&gt;&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;&lt;a name="TheDeploymentScript"&gt;2.2 The Deployment script&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;We used a PowerShell script to manage the process of deploying, in the correct order, our databases, SSIS packages and analysis cubes. The script, which my colleagues had created, used a configuration file to list the artefacts for deploying with how and where. Also the script interaction used a text menu interface, which was created from the following location: &lt;a href="http://mspowershell.blogspot.com/2009/02/cli-menu-in-powershell.html"&gt;http://mspowershell.blogspot.com/2009/02/cli-menu-in-powershell.html&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This was helpful in reducing the work that we had to do for writing a release process. As we only had to write was: select menu option blah, select menu option blah etc. The script help reduce deployment errors from incorrect commands typed in or artefacts deployed in the wrong order.&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-qx2ApLG0VFI/TpxVS_o5KVI/AAAAAAAAAHc/XM6FdG0faBA/s1600-h/Automation35.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Automation - Execution" border="0" alt="A running nan" src="http://lh3.ggpht.com/-gslaxDFLw2Y/TpxVTQPtPgI/AAAAAAAAAHk/A4yrgOSwC-A/Automation3_thumb3.png?imgmax=800" width="333" height="87"&gt;&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;&lt;a name="AutomatedDeploymentAndExecution"&gt;2.3 Automated deployment and execution&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;To have the automated build, deployment and execution process I reuse the build and deployment components. The build was refactored and reused within a scheduled trigger for out of office hours. The deployment script was extended to include support being called by automation tool. The automation tool was called TFSDeployer. TFSDeployer is a service which can be configured to listen for certain build events and then run a powershell script when captured. For more details about the application, please use the following link: &lt;a href="http://tfsdeployer.codeplex.com/"&gt;http://tfsdeployer.codeplex.com/&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;The script, which TFSDeployer would execute, when the out of office build completed, was configured to do the following steps:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Get the TFS build details.  &lt;li&gt;Copy the contents of the build drop location to a deployment area.  &lt;li&gt;Deploy the data warehouse solution using the deployment script  &lt;li&gt;If the deployment failed then update the TFS build to failed and the status to broken  &lt;li&gt;If the deployment was successful then execute a SQL Server job; which was configured to run the ETL.  &lt;li&gt;If the SQL Server job reported failure then the TFS build was set as failed and the status to broken  &lt;li&gt;If the SQL job reported success then the TFS build was set as successful and the status set for ready for testing &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;This then gave us the ability to test our builds and as mentioned before allowed us to find many problems before we went into UAT. This also gave us a platform to perform and automate regression testing.&lt;/p&gt; &lt;h4&gt;&lt;a name="VisualStudioTips"&gt;3 Visual studio tips&lt;/a&gt;&lt;/h4&gt; &lt;h4&gt;&lt;a name="ReducingUnresolveReferenceErrors"&gt;3.1 Reducing unresolve reference &lt;/a&gt;warnings&lt;/h4&gt; &lt;p&gt;Here are some tips on how we managed to reduce some of our unresolved reference warnings.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Converting some of derived tables to use common table expression with column definition syntax: WITH &amp;lt;CTEName&amp;gt;(Col1, Col2, Col3) AS  &lt;li&gt;Adding a server and database variables for references which were going to go to be referred to via a link server. Within the code also wrapped the reference variables within square brackets.  &lt;li&gt;Include objects which were created by code for example: select into tables and indexes. With indexes we also took another approach, where possible, which was to disable and enable them. &lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;&lt;a name="CompositeProjects"&gt;3.2 Composite Projects&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;During one of our early development cycles we came across a circular reference problem. This caused a problem at deployment time. I had to deploy the two databases about three times each to get a complete deployment.&lt;/p&gt; &lt;p&gt;The method I used to reduce a circular reference to happen was to use composite projects. The way I chose to split databases into composite projects was to put the storage objects like tables into one project. Then created another project for the code objects like views and referenced the storage project. The idea for this was based on some information I read from: &lt;a href="http://vsdatabaseguide.codeplex.com/"&gt;http://vsdatabaseguide.codeplex.com/&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;&lt;a name="Resources"&gt;4 Resources&lt;/a&gt;&lt;/h4&gt; &lt;ul&gt; &lt;li&gt;Power Shell Menu functions: &lt;a href="http://mspowershell.blogspot.com/2009/02/cli-menu-in-powershell.html"&gt;http://mspowershell.blogspot.com/2009/02/cli-menu-in-powershell.html&lt;/a&gt;  &lt;li&gt;TFSDeployer: &lt;a href="http://tfsdeployer.codeplex.com/"&gt;http://tfsdeployer.codeplex.com/&lt;/a&gt;  &lt;li&gt;Team Foundation Server Update script:  &lt;li&gt;Run SQL Server Job:&lt;a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/.Public/BlogPostFiles/PowerShell/SQLServer2008R2RunJob.ps1?cid=e6f77d4b3ff8d47c&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/.Public/BlogPostFiles/PowerShell/TeamFoundationServer.ps1?cid=e6f77d4b3ff8d47c&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-1773283261669082223?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/1773283261669082223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=1773283261669082223' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1773283261669082223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1773283261669082223'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2011/10/business-intelligence-project-alm.html' title='A Business Intelligence project ALM&amp;#39;s'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/-VUG5U7Llkzo/TpxVRiCisWI/AAAAAAAAAHI/vKI5kUje6Fs/s72-c/Automation1_thumb4.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-5593655397785224825</id><published>2011-10-17T15:29:00.001+01:00</published><updated>2011-10-17T17:09:01.646+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Rules Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Integrating a rules engine with integration services</title><content type='html'>&lt;h4&gt;Introduction&lt;/h4&gt;As I have mentioned in several previous posts, I have been working on a data warehouse project. One of my main roles within this project was to work with our clients JRules / Java consultants to help integrate IBM JRules, a rules engine, with Microsoft SQL Server 2008 R2: Integration Services (SSIS).&lt;br /&gt;The goal of the integration was to have the rules engine as part of the ETL process to help evaluate business rules. The reasons to use a rules engine within the ETL process were as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;To allow business people to write the business rules for the data warehouse in a language they know: English  &lt;/li&gt;&lt;li&gt;To give the business people the responsibility for maintaining the rules to ensure that the data warehouse is up to date.  &lt;/li&gt;&lt;li&gt;To be able to update the rules without having to deploy the entire ETL solution. &lt;/li&gt;&lt;/ul&gt;IBM JRules was used within the project because it was already in use within their organisation. The challenge was how to cross the divide between Java and Microsoft .Net.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Options to consider for integrating with the rules engine&lt;/h4&gt;Below is a list of options which I and some of my other colleagues thought about on how to integrate JRules and SSIS&lt;br /&gt;&lt;ul&gt;&lt;li&gt;How the rules engine will access the data.  &lt;ul&gt;&lt;li&gt;Receiving the data: Should the data be supplied with the request to execute the rule engine.  &lt;/li&gt;&lt;li&gt;Reading the data: Is the rules engine responsible for reading the data when requested to run. &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Which processing method  &lt;ul&gt;&lt;li&gt;Batch: Process a batch of data within the rules engine.  &lt;/li&gt;&lt;li&gt;Row by Row: Make separate requests to the rules engine row by row. &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The communication / execution method  &lt;ul&gt;&lt;li&gt;Using Web Services method, Restful Services method.  &lt;/li&gt;&lt;li&gt;Directly coding against the rules engine API libraries. For our integration we would have to have used some sort of interoperability classes like: JNBridge, JIntegra. &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;How to apply the results of the rule engine. Does the rule engine apply the results directly or are they returned to the ETL for processing.  &lt;/li&gt;&lt;li&gt;Error handling  &lt;ul&gt;&lt;li&gt;Rules engine errors: how to record the errors from the rule engine.  &lt;/li&gt;&lt;li&gt;Integration errors: how to handle errors caused by a failure of the integration.&amp;nbsp; &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Our approach&lt;/h4&gt;Our approach to the integration was to use a batch process model with a SOAP Web method for triggering the rule processing. The rule processing would be responsible for reading, processing and recording the results of the rules execution. The SSIS packages would prepare the batch of data; trigger the rule processing and then process the results. Below is a diagram to illustrate the integration approach:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh5.ggpht.com/-jctnkF-yXI8/Tpw7vTwv9dI/AAAAAAAAAGo/mJBPhLRxkpk/s1600-h/SSISIntergationJRules5.png"&gt;&lt;img alt="SSISIntergationJRules" border="0" src="http://lh3.ggpht.com/-pWmE4usAfEQ/Tpw7vzfDFqI/AAAAAAAAAGw/Cyc2H50DsxI/SSISIntergationJRules_thumb2.png?imgmax=800" style="background-image: none; border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="SSISIntergationJRules" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Web service method&lt;/u&gt;&lt;br /&gt;The web service method, which was written by our clients JRules/Java consultants, was defined with the following parameters: the batch identifier; the name of the collection of rules for evaluation.&lt;br /&gt;This method would then start running the rules processing procedures which are as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;start reading the data  &lt;/li&gt;&lt;li&gt;execute the rules over each complete source row once fetched  &lt;/li&gt;&lt;li&gt;store the results back to the database &lt;/li&gt;&lt;/ul&gt;After the completion of the rule processing the web service method would give a response indicating the success of the rules execution. The web service method was optimise to use multiple threads and to stream read the data. Also the way that the rules are implemented within JRules also helps to optimise the rule processing.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Data Integration&lt;/u&gt;&lt;br /&gt;The way that we passed data between SSIS and JRules was to use a couple of tables, which use a name value pair structure. One table, Inbound, was used to store the prepared data for rule processing. The other table, Outbound, to store the results from rule processing which the SSIS would process. &lt;br /&gt;The reasons to use a generic structure are as follows: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;If the rules parameters changed then only the ETL process would need to be updated  &lt;/li&gt;&lt;li&gt;The rule integration was easier to code  &lt;/li&gt;&lt;li&gt;To have the integration only use two tables to help debugging &lt;/li&gt;&lt;/ul&gt;&lt;u&gt;SSIS Integration&lt;/u&gt;&lt;br /&gt;SSIS packages would be responsible for creating the batch data. Afterwards trigger the rules engine processing method and wait for the response. Once the response was received the results would be applied or/and log any errors. &lt;br /&gt;The method I use to call the Web method was to write a .Net control flow component. The main reason I chose to write a component was to have easier code reuse. Also maintenance was easier as I only had to update one component and all packages would pick up the new component. &lt;br /&gt;The approach I took with my custom component was to separate the SSIS integration and the actual call to the web service. Creating a code library that handled the interaction with the web service. This was then wrapped with another code library that handled the SSIS integration.&lt;br /&gt;Taking this approach also allowed me to write a console application to test the interaction with the rules engine using the same calling code as the packages would use. This console application allowed us to debug any integration problems that we came across.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Integration results&lt;/h4&gt;Currently we are able to process a batch of 100,000 source rows within a five minute period. This is adequate for a normal day runs where we would only have to process changes for a day. However when there is a requirement to re-run the rules against entire warehouse data the process can take a little while. This is because a number of batches are required to complete the rules processing. There is an improvement currently being investigated, by another team member, to reduce the amount of data sent to the rule engine for processing. The method which is currently being looked at is as follows: Find the unique rows to send to the rules engine for processing and then apply the results back to the required rows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-5593655397785224825?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/5593655397785224825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=5593655397785224825' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5593655397785224825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5593655397785224825'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2011/10/integrating-rules-engine-with.html' title='Integrating a rules engine with integration services'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-pWmE4usAfEQ/Tpw7vzfDFqI/AAAAAAAAAGw/Cyc2H50DsxI/s72-c/SSISIntergationJRules_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3999545525284107888</id><published>2011-09-21T13:02:00.001+01:00</published><updated>2011-09-21T13:15:28.472+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Master Data Services'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='MDS'/><title type='text'>Comparing Master Data Services instances</title><content type='html'>As I have mentioned in previous posts, I've been working on a data warehouse project. Within the project we decided to use SQL Server 2008 R2 Master Data Services (MDS) to store all the warehouse specific reference data. Here are some reasons why MDS was used:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Allowed us to manage the reference data. &lt;/li&gt;&lt;li&gt;Reference data could be loaded into the warehouse like a source system &lt;/li&gt;&lt;li&gt;Would allow the client’s data governance team to easily update the reference data and keep the warehouse up-to-date &lt;/li&gt;&lt;/ul&gt;For active development of entities and data loads we use a sandpit instance. When the ETL was ready to use the new entities or loaded data, a cut of the sandpit instance would be promoted to the development environment. We came across a problem when we needed to identify some changes which were accidentally made on the development instance.&lt;br /&gt;&lt;br /&gt;I came up with a method which helped to identify the changes fairly easily, below is the method I used. I will say that it’s not a perfect solution and might not work for everyone or continue to work when MDS updates have been applied.&lt;br /&gt;&lt;br /&gt;Run the following SQL script on both instance of the MDS database servers:&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; MDSCompare&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vColList &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(&lt;span class="kwrd"&gt;MAX&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vViewName &lt;span class="kwrd"&gt;AS&lt;/span&gt; SYSNAME&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vSQL &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(&lt;span class="kwrd"&gt;MAX&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vEntityID &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vModelID &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt; = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; id &lt;span class="kwrd"&gt;FROM&lt;/span&gt; mdm.tblModel &lt;span class="kwrd"&gt;where&lt;/span&gt; Name = &lt;span class="str"&gt;'&amp;lt;ModelName,Char,Master Data&amp;gt;'&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; EntityID_Cursor &lt;span class="kwrd"&gt;CURSOR&lt;/span&gt; &lt;span class="kwrd"&gt;LOCAL&lt;/span&gt; FORWARD_ONLY FAST_FORWARD READ_ONLY&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;FOR&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; ID &lt;span class="kwrd"&gt;FROM&lt;/span&gt; mdm.tblEntity e &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; model_id= @vModelID &lt;span class="kwrd"&gt;order&lt;/span&gt; &lt;span class="kwrd"&gt;by&lt;/span&gt; id&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="kwrd"&gt;OPEN&lt;/span&gt; EntityID_Cursor&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&lt;span class="kwrd"&gt;FETCH&lt;/span&gt; &lt;span class="kwrd"&gt;NEXT&lt;/span&gt; &lt;span class="kwrd"&gt;FROM&lt;/span&gt; EntityID_Cursor&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&lt;span class="kwrd"&gt;INTO&lt;/span&gt; @vEntityID&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHILE&lt;/span&gt; &lt;span class="preproc"&gt;@@FETCH_STATUS&lt;/span&gt; = 0&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @vViewName = REPLACE(e.Name,&lt;span class="str"&gt;' '&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;         , @vColList  = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(@vColList + &lt;span class="str"&gt;', ['&lt;/span&gt; + a.name + ISNULL(&lt;span class="str"&gt;'_'&lt;/span&gt; + la.name,&lt;span class="str"&gt;''&lt;/span&gt;) +&lt;span class="str"&gt;']'&lt;/span&gt;, &lt;span class="str"&gt;'['&lt;/span&gt; + a.name + ISNULL(&lt;span class="str"&gt;'_'&lt;/span&gt; + la.name,&lt;span class="str"&gt;''&lt;/span&gt;) +&lt;span class="str"&gt;']'&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; mdm.tblAttribute a&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;        &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; mdm.tblEntity e&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            &lt;span class="kwrd"&gt;ON&lt;/span&gt; e.id = a.entity_id&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; mdm.tblAttribute la&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;            &lt;span class="kwrd"&gt;ON&lt;/span&gt; a.domainEntity_Id = la.entity_id&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;            &lt;span class="kwrd"&gt;AND&lt;/span&gt; la.attributeType_id = 1&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;            &lt;span class="kwrd"&gt;AND&lt;/span&gt; la.IsSystem = 1&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; a.entity_id = @vEntityID   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    &lt;span class="kwrd"&gt;AND&lt;/span&gt; a.attributeType_id &amp;lt;&amp;gt; 3&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @vSQL = &lt;span class="str"&gt;'SELECT '&lt;/span&gt; + @vColList + &lt;span class="str"&gt;' INTO MDSCompare.dbo.'&lt;/span&gt; + @vViewName + &lt;span class="str"&gt;' FROM mdm.'&lt;/span&gt; + @vViewName&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;    &lt;span class="kwrd"&gt;EXEC&lt;/span&gt; (@vSQL)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;    &lt;span class="kwrd"&gt;FETCH&lt;/span&gt; &lt;span class="kwrd"&gt;NEXT&lt;/span&gt; &lt;span class="kwrd"&gt;FROM&lt;/span&gt; EntityID_Cursor&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @vEntityID&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @vColList = &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;        , @vViewName = &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;        , @vSQL = &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;       &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;&lt;span class="kwrd"&gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;&lt;span class="kwrd"&gt;CLOSE&lt;/span&gt; EntityID_Cursor&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;&lt;span class="kwrd"&gt;DEALLOCATE&lt;/span&gt; EntityID_Cursor&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then to test that all the entity which are required have been created use the following script: &lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vModelID &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt; = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; id &lt;span class="kwrd"&gt;FROM&lt;/span&gt; mdm.tblModel &lt;span class="kwrd"&gt;where&lt;/span&gt; Name = &lt;span class="str"&gt;'&amp;lt;ModelName,Char,Master Data&amp;gt;'&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;;&lt;span class="kwrd"&gt;WITH&lt;/span&gt; MDSEntity(Entityname)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;(&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="kwrd"&gt;select&lt;/span&gt; REPLACE(e.Name,&lt;span class="str"&gt;' '&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;)  Entityname&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="kwrd"&gt;from&lt;/span&gt; mdm.tblEntity e &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; model_id= @vModelID&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;, CompareTables (TableName)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;(&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; Table_Name&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; MDSCompare.INFORMATION_SCHEMA.TABLES t&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;where&lt;/span&gt; t.table_schema = &lt;span class="str"&gt;'dbo'&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; *&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; MDSEntity e&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; CompareTables c&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="kwrd"&gt;ON&lt;/span&gt; e.Entityname = c.TableName&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; c.TableName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then use the visual studio 2010 schema compare tool against the two instances of the MDSCompare databases to highlight any structural changes which have been made to the entities.&lt;br /&gt;&lt;br /&gt;To find data changes use the following script on the MDSCompare databases to create primary keys: &lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; MDSCompare&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'ALTER TABLE ['&lt;/span&gt; + table_schema + &lt;span class="str"&gt;'].['&lt;/span&gt; + table_name + &lt;span class="str"&gt;'] WITH NOCHECK ADD CONSTRAINT PK_'&lt;/span&gt; + table_name+&lt;span class="str"&gt;'_Code PRIMARY KEY CLUSTERED (Code)'&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; INFORMATION_SCHEMA.COLUMNS&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; column_name = &lt;span class="str"&gt;'code'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then use the visual studio 2010 data compare tool to highlight any data differences. &lt;br /&gt;&lt;br /&gt;While using the above methods to do the comparisons I found some differences which I had to ignore. The reason we had to ignore them was because of the following scenario: &lt;br /&gt;&lt;br /&gt;While loading data through the batch staging process we had to set the default name attribute of the entities to be an empty string. This is because it would not allow nulls and we did not want to use this attribute. However the development instance has the default name attribute set with nulls. I believe this was because the MDS deployment tool had converted the empty element of the deployment package, which was created because of the empty string, to null while uploading.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3999545525284107888?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3999545525284107888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3999545525284107888' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3999545525284107888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3999545525284107888'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2011/09/comparing-master-data-services.html' title='Comparing Master Data Services instances'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-6502720462494524829</id><published>2011-09-19T13:26:00.001+01:00</published><updated>2011-10-17T15:52:54.634+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Change Data Capture'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='CDC'/><title type='text'>Choosing the right CDC tool for the job</title><content type='html'>&lt;h4&gt;Introduction&lt;/h4&gt;I have, as mentioned in a &lt;a href="http://zogamorph.blogspot.com/2011/09/source-system-data-to-warehouse-via-cdc.html" target="_blank"&gt;previous blog&lt;/a&gt;, been working on a data warehouse project using CDC for extracting the source system data. I would like to share some of the experiences and evaluation criteria used for selecting a CDC tool for our project.&lt;br /&gt;The reason for using a specialist tool was as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Couldn't move all the source databases to SQL Server 2008 &lt;/li&gt;&lt;li&gt;Needed the capture change data to be sent to another server instance &lt;/li&gt;&lt;li&gt;A consistent management experience for CDC between all our source systems. The two database vendors the tool needed to support was SQL Server and IBM AS400 &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Timescales&lt;/h4&gt;First we underestimated how long it would take to select a CDC tool. We plan for 1 month, for both evaluation criteria and running the tests, and it took us about 2/3 months. The time was taken in evaluating the tools against the criteria and gaining access to database systems from other projects.&lt;br /&gt;However our development of the ETL solution was able to continue, while the CDC tool hadn’t been selected, as we used generic columns for the CDC metadata. Our requirements allowed this approach because only a selected set of metadata was needed from the CDC tool which most tools offered. The method to ensure that the changes were picked up in the right order was to use a row ID, which was a big integer identity seed, within the CDC destination table. This was able to work as most CDC tool records the changes in the same order as they are made.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Evaluation criteria&lt;/h4&gt;Here are some categories of criteria, which our client used, to select which CDC tool to evaluate, these are common sense categories:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Impact: How CDC would impact both source and target systems servers and databases. The Server impact was measured in how much resources it would take to use on the server: memory, CPU, etc. &lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;The database impact was whether it made any schema changes and if it had performance implications for the application. This was important to know as there was a third-party tool where the support contract would have been invalidated if any schema changes were made to their database. To tests for schema changes I use a simple procedure which was to use VSDBCMD tool to import the schema into a schema file before installing CDC. After the install import again to another file and use VS2010 schema compare tool to compare against the schema files.&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Schema changes: Does the CDC tool cope with schema changes being made on the source system. Could the tool continue to work if the schema changes were made onto columns which weren't being captured or if any new columns were added. &lt;/li&gt;&lt;li&gt;Speed: How quickly were changes committed to the target server. The metrics for this was by the volume of changes and speed to commit them. Also how quickly the initial synchronisation took to complete. &lt;/li&gt;&lt;li&gt;Management: What was the management tool, how easy was the management tool to use, how quickly CDC was recoverable from errors or disasters. &lt;/li&gt;&lt;/ul&gt;While evaluating CDC tool we also found that we had to consider some other factors. One consideration was how it impacted the operational procedures of the source systems, for example backups, recovery and deployments.&lt;br /&gt;Another factor was the number of databases and tables which we wanted to capture data from. We had 20 source databases, which had about 15 tables each. Depending on the CDC tool more time would have to be spent on the development and deploying the CDC solution.&lt;br /&gt;&lt;br/&gt;&lt;b&gt;To develop or to configure that is the question?&amp;nbsp; (sorry couldn't resist the Shakespeare pun)&lt;/b&gt;&lt;br /&gt;That is the question that we found ourselves asking. As some tools required development of code to create a CDC solution. Also with the tools which required development the experience and environment had to be considered as part of the evaluation. Such as the level of privileges required on the development computer; is there any integration with source control or how to protect from loss of work; how easy is it to transfer development from one developer to another. &lt;br /&gt;Another aspect of the CDC tools evaluation was how easy it was to deploy from our development environment to production. How easy was the CDC solution to deploy and was there any automation through scripting or exporting.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Observations&lt;/h4&gt;While evaluating we found the same tool gave a different level of change data capture experience depending on the database vendor it was configured against. For example: when configured against the AS400 the tool was able to give a full row of data. But when configured against and SQL server it was only able to give the columns which had changed. The reason for this was how the tool had implemented CDC for the SQL server. There was no requirement for the replication components for SQL server to be installed, without this component the SQL server log file only records the columns which had changed. Hence why the tool was only able to give only the change columns data and not the full row of data.&lt;br /&gt;We also found that the same CDC tool behaved differently when running against different processing editions (x86 and x64). The difference was with settings and memory requirements.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Useful links&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Attunity - &lt;a href="http://www.attunity.com/index.aspx"&gt;http://www.attunity.com/index.aspx&lt;/a&gt; - which have arrange of CDC products &lt;/li&gt;&lt;li&gt;DBMoto - &lt;a href="http://www.hitsw.com/products_services/dbmoto/dbmoto_dsheet.html"&gt;http://www.hitsw.com/products_services/dbmoto/dbmoto_dsheet.html&lt;/a&gt; &lt;/li&gt;&lt;li&gt;IBM InfoSphere Change Data Capture - &lt;a href="http://www-01.ibm.com/software/data/infosphere/change-data-capture"&gt;http://www-01.ibm.com/software/data/infosphere/change-data-capture&lt;/a&gt; &lt;/li&gt;&lt;li&gt;Oracle golden gate - &lt;a href="http://www.oracle.com/technetwork/middleware/goldengate/overview/index.html"&gt;http://www.oracle.com/technetwork/middleware/goldengate/overview/index.html&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-6502720462494524829?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/6502720462494524829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=6502720462494524829' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6502720462494524829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6502720462494524829'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2011/09/choosing-right-cdc-tool-for-job.html' title='Choosing the right CDC tool for the job'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-5575005472789040963</id><published>2011-09-19T13:14:00.001+01:00</published><updated>2011-10-17T15:48:56.977+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Change Data Capture'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='CDC'/><title type='text'>Source system data to warehouse via CDC.</title><content type='html'>&lt;h4&gt;Introduction&lt;/h4&gt;I have been working on a data warehouse project with a difference. The difference is that the ETL is not doing the classic extract of source system data, instead the source system is going to send its data to the data warehouse by using change data capture (CDC). The decision for using CDC was as follows: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;To have the ETL only process the data that has changed within the source system between each run of the ETL. This would help the ETL perform as it would only have to process the change data and not work out what the changes were first.  &lt;/li&gt;&lt;li&gt;Not to have the ETL processes impact the central source system database. The CDC would be responsible for delivering the changes of the source system to another database server. Then the ETL could be run at any time within the day and wouldn't be responsible for blocking the transactional source system. As there was plans to have the ETL run at the end of the day for two time zones e.g. US and UK. &lt;/li&gt;&lt;/ul&gt;I would like to share some of the experiences, decisions and challenges that we face while trying to build a data warehouse using CDC. The first decision, which I will put into &lt;a href="http://zogamorph.blogspot.com/2011/09/choosing-right-cdc-tool-for-job.html" target="_blank"&gt;another post&lt;/a&gt;, was which CDC software to use. As a consequence of using CDC we faced a challenge on how to extract data from source systems where CDC couldn't be applied, One such system was Master Data Services (MDS) this was due to how the data is stored within its database. As this would mean the transforms for this source system would have to use a different approach to where CDC was used. What we decided to do was mocked CDC through use of SSIS and then stored the delta changes that we found through our dataflow process. The reason for choosing this approach was so that all the transforms had a consistent approach.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Development&lt;/h4&gt;Early into development we discovered that we had to define what was meant by processing intraday changes. Did this mean every row which was captured by CDC within that Day? In other words, that every change which was captured should create a history change within the data warehouse leaving the last change as current. Or did this mean capture events changes within the day? For example scanned the changes for that day and find the flags for the records that are required. For us this meant capture event changes. Importance of understanding the meaning of intraday changes had an impact on how we approached coding the transform procedures.&lt;br /&gt;&lt;br /&gt;Another challenge that we faced was how to deal with transforms which require data from two tables. The reason why this was a challenge is because of the following scenario: An entity within the warehouse has a business rule which requires data from 2 tables from the source system before it can be evaluated. However within the source system data has been changed and captured for one table only. For example: business rule order status requires data from the OrderHeader table and the OrderLine table.&amp;nbsp; As illustrated below.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/-gPrdYtQ9Wdw/TncyJpXuKZI/AAAAAAAAAGY/x5DWyfafbTs/s1600-h/BusinessRules6.png"&gt;&lt;img alt="BusinessRules" border="0" src="http://lh5.ggpht.com/-l5s5p34QX94/TncyKIYRnZI/AAAAAAAAAGc/ngBnZN7OAjg/BusinessRules_thumb4.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="BusinessRules" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The source system updates the OrderLine table and a CDC captures the changes and sends them to the ETL. Then the ETL process runs with only the OrderLine changes tries to evaluate the order status business rule but how to evaluate this when OrderHeader data has not been supplied? As illustrated below.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh6.ggpht.com/-kCPsRJBYk7I/TncyKiA8CUI/AAAAAAAAAGg/F8Cj4PTUuns/s1600-h/MissingBusinessRules9.png"&gt;&lt;img alt="MissingBusinessRules" border="0" src="http://lh3.ggpht.com/-8sX3yMSrnH4/TncyLN-DTnI/AAAAAAAAAGk/wt8VJzDvKy8/MissingBusinessRules_thumb5.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="MissingBusinessRules" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;There are many ways this can be resolved, here are some examples: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Change the application process to create updates to the required linked tables. This might not solve the problem as the CDC software may not have committed all of the changes before the ETL process starts running, unless the CDC is part of the ETL.&amp;nbsp; Also this may cause performance problems for the application team.  &lt;/li&gt;&lt;li&gt;To design the data warehouse scheme and business rules so that the transforms don't require joins between tables to create a data warehouse. This I will highlight may not be practical as it could mean it basically becomes a copy of source systems schemas which would give you no value for reporting and analysing.  &lt;/li&gt;&lt;li&gt;To get transform to read the missing data from the data warehouse if CDC hasn’t passed on the data. This was a good option to consider however there are few considerations to be aware of:  &lt;ul&gt;&lt;li&gt;Could have performance issues with the transform for some of the following reason: Using left outer joins on warehouse tables and depending on the warehouse schema could require a large number of tables; have use of function calls to IsNull or Coalesce; The size of the tables data warehouse could make query tuning very difficult.  &lt;/li&gt;&lt;li&gt;Adding complexity to untranslate business rules or transforms if source system data isn’t being natively stored  &lt;/li&gt;&lt;li&gt;Harder to read and maintain as the transform isn’t just transforming source data  &lt;/li&gt;&lt;li&gt;The data warehouse could become even wide or larger if the source systems native data is stored within the warehouse to help the transform.&amp;nbsp; This will have an impact for querying and processing performance; also add overhead cost for storage. &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;We solve the problem by extending one of our client's requirements. The requirement was: keep a copy of the source system data changes for each day for a further 30 days. To meet this we configured the CDC to send all the changes to an archive database. Then have the ETL process to extract the day changes from the archive database. Rather than have CDC drop the changes to a landing database and then have the ETL copy the data again to the archive database as well as transform the data. The extension of the requirement was to keep all changes of the latest version of each primary key within the archive database. This then allowed us to write a post-extract process to extract any missing data required for any of the transforms where data wasn't present. This then allowed us to write the transforms in a manner that always assumed that all data was in the same location.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Testing &lt;/h4&gt;We found that we had to change the way that we prepared to test our ETL process by using datasets. Normally we would create some datasets which would mirror the source system in a particular state for testing certain scenarios for transforms and business rules. However this time we only needed to create change records for testing but the problem was how to ensure that the change records were fed in a controlled manner to ensure consistent mirrored states of source system and valid transitions were maintained. We resolved this problem by investing time to create a test harness solution. Which mimic our CDC tool of choice by inserting the test data into the archive database and then running the ETL process. One thing I would recommend is that you trial your CDC tool over your source systems to see what data changes will be actually captured. This will help to create valid test data for testing transforms and business rules within your ETL process&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Related posts.&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://zogamorph.blogspot.com/2011/09/choosing-right-cdc-tool-for-job.html" target="_blank"&gt;Choosing the right CDC tool for the job&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-5575005472789040963?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/5575005472789040963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=5575005472789040963' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5575005472789040963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5575005472789040963'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2011/09/source-system-data-to-warehouse-via-cdc.html' title='Source system data to warehouse via CDC.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/-l5s5p34QX94/TncyKIYRnZI/AAAAAAAAAGc/ngBnZN7OAjg/s72-c/BusinessRules_thumb4.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-6187709045675791863</id><published>2010-04-09T08:16:00.001+01:00</published><updated>2010-04-09T08:16:02.479+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SharePoint 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerPivot'/><title type='text'>Configuring Excel Services &amp; PowerPivot on multi server Topology</title><content type='html'>&lt;p&gt;I have been working with a couple of colleagues, &lt;a href="http://consultingblogs.emc.com/jamesdawson/" target="_blank"&gt;James Dawson&lt;/a&gt; and &lt;a href="http://consultingblogs.emc.com/russellseymour/" target="_blank"&gt;Russell Seymour&lt;/a&gt; , on installing and configuring PowerPivot within a SharePoint 2010 beta 2 farm. &lt;/p&gt;  &lt;p&gt;We used the following instructions to install PowerPivot on one of the application tier server: &lt;a title="http://msdn.microsoft.com/en-us/library/ee210616(SQL.105).aspx" href="http://msdn.microsoft.com/en-us/library/ee210616(SQL.105).aspx"&gt;http://msdn.microsoft.com/en-us/library/ee210616(SQL.105).aspx&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;After following the instructions we were able to verify the installation as we had a SharePoint site with PowerPivot gallery.&amp;#160; We managed to uploaded and open a couple of Excel workbooks, with PowerPivot embedded, within the web browser.&amp;#160; Also we were able to connect to the PowerPivot service and could see the PowerPivot data files loaded. When I tested the slicers I got greeted with the following error: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S77UK15EdLI/AAAAAAAAAFM/Mji9A_AJABc/s1600-h/ExcelServicesError16.png" target="_blank"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="The data connection uses Windows Authentication and Excel Services is unable to delegate user credentials. The following connections failed to refresh: Sandbox" border="0" alt="The data connection uses Windows Authentication and Excel Services is unable to delegate user credentials. The following connections failed to refresh: Sandbox" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S77ULacT_wI/AAAAAAAAAFQ/jHbKn3kPiEo/ExcelServicesError1_thumb4.png?imgmax=800" width="322" height="224" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;We did some research and found the following blog post: &lt;a title="http://powerpivotgeek.com/2009/12/11/excel-services-delegation/" href="http://powerpivotgeek.com/2009/12/11/excel-services-delegation/"&gt;http://powerpivotgeek.com/2009/12/11/excel-services-delegation/&lt;/a&gt;.&amp;#160; I implemented the changes it recommended to our Excel workbooks and tried again this time getting the following error: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S77ULtuEd9I/AAAAAAAAAFU/bjJIThmJjmI/s1600-h/ExcelServicesError6.png" target="_blank"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="The data connection uses None as the external data authentication method and Unattended Services has not been configured on Excel Services. The following connections failed to refresh: Sandbox" border="0" alt="The data connection uses None as the external data authentication method and Unattended Services has not been configured on Excel Services. The following connections failed to refresh: Sandbox" src="http://lh5.ggpht.com/_CJNik6Tu6JU/S77UMeTtAtI/AAAAAAAAAFY/jeucsAaIAKM/ExcelServicesError_thumb4.png?imgmax=800" width="318" height="231" /&gt;&lt;/a&gt;However at the time of this error we had already configured the Excel Services with the Secure Store Service application identity that we had created.&amp;#160; &lt;/p&gt;  &lt;p&gt;The problem proved to be with the configuration of all the service applications. At the start all the services applications had their own application pools with there own domain users.&amp;#160; &lt;/p&gt;  &lt;p&gt;The solution in the end was to run all the services applications under the following app pool configuration: SharePoint Web Services System. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-6187709045675791863?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/6187709045675791863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=6187709045675791863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6187709045675791863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6187709045675791863'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/04/configuring-excel-services-powerpivot.html' title='Configuring Excel Services &amp;amp; PowerPivot on multi server Topology'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_CJNik6Tu6JU/S77ULacT_wI/AAAAAAAAAFQ/jHbKn3kPiEo/s72-c/ExcelServicesError1_thumb4.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4284043698131912850</id><published>2010-03-09T18:44:00.000Z</published><updated>2010-03-21T22:35:37.423Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Replication'/><category scheme='http://www.blogger.com/atom/ns#' term='Merge Replication'/><category scheme='http://www.blogger.com/atom/ns#' term='Regular Expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='Transaction Replication'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerShell'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Using Powershell to understand a replication topology</title><content type='html'>&lt;p&gt;I recently had to investigated a client replication topology.&amp;#160; I needed to understand the publications, subscribers and the articles. The problems I was facing were as follows: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The replication topology was only defined on the production infrastructure. &lt;/li&gt;    &lt;li&gt;There was no documentation about the replication topology.&lt;/li&gt;    &lt;li&gt;I had no way of being able re-create replication topology. &lt;/li&gt;    &lt;li&gt;Only short amount of time. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I was able to script the replication topology from the SQL Server Management Studio.&amp;#160; This was partially helpful as I now had a script which could be used to review the replication topology.&amp;#160; However this end up being a fairly large file and would be time consuming to review all information.&amp;#160; &lt;/p&gt;  &lt;p&gt;So I deicide to write a PowerShell, SQL Server Powershell for the Invoke-Sqlcmd commandlet, that would do the following steps: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Parse the file to find the lines containing the following store procedures:      &lt;ul&gt;       &lt;li&gt;sp_addarticle. &lt;/li&gt;        &lt;li&gt;sp_addsubscription. &lt;/li&gt;     &lt;/ul&gt; As theses contain most useful parameters to help understand the replication topology &lt;/li&gt;    &lt;li&gt;Pares the line to find the key parameters and their values. &lt;/li&gt;    &lt;li&gt;Then insert the information into tables within a database. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I chose to use PowerShell because this was a perfect fit for a scripting language: manipulating a text file and doing regular expression on strings. &lt;/p&gt;  &lt;p&gt;This help me see that articles were being repeated across publication, some of the publication had identical articles but had different subscriber. &lt;/p&gt;  &lt;p&gt;A copy of powershell script is available &lt;a href="http://cid-e6f77d4b3ff8d47c.skydrive.live.com/self.aspx/.Public/GetReplicationInfo.ps1" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4284043698131912850?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4284043698131912850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4284043698131912850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4284043698131912850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4284043698131912850'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/03/using-powershell-to-understand.html' title='Using Powershell to understand a replication topology'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-708020054578723890</id><published>2010-01-22T21:33:00.000Z</published><updated>2010-02-18T21:34:17.167Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v3'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><title type='text'>How To: Emailing the Sprint Burndown report</title><content type='html'>&lt;p&gt;The &lt;a href="http://www.scrumforteamsystem.com/"&gt;Scrum for Team System&lt;/a&gt; process template includes reports to help manage the progress of project.&amp;#160; The onus is on the team to run - by opening them - and review them.&amp;#160; This is the default behaviour of the Team Foundation Server which our process template built against, however as the Team Foundation Server platform uses SQL Server Reporting Services for its reporting software, the reports can actually be pushed out to the teams via e-mail.&amp;#160; &lt;/p&gt;  &lt;p&gt;I have mentioned how to do this for version 2.x, and for version 1.x the same steps can be applied, with the following post:&amp;#160; &lt;a href="http://consultingblogs.emc.com/stevewright/archive/2008/02/19/How-E_2D00_mail-the-Sprint-Burndown-Chart-to-yourself-or-your-team_2E00_.aspx"&gt;How to E-mail the Sprint Burndown Chart to yourself or your team.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;For version 3.0 (For which beta 2 is now available for download from the following link: &lt;a href="http://scrumforteamsystem.com/cs/forums/4554/ShowPost.aspx"&gt;http://scrumforteamsystem.com/cs/forums/4554/ShowPost.aspx&lt;/a&gt; ) things are a little different.&lt;/p&gt;  &lt;p&gt;Firstly, if not already configured, the Reporting Services server will need to will need to be set up to point to an SMTP server. This can be done by using the Reporting Services configuration tool and updating the e-mail settings within this tool.&amp;#160;&amp;#160; You can find this tool on your TFS report server under the following: Start Menu &amp;gt; Programs &amp;gt; Microsoft SQL Server 2008 &amp;gt; Configuration Tools &amp;gt; Reporting Services Configuration Manager&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32yS1Oh1-I/AAAAAAAAAEw/8mGIUx1ybCg/s1600-h/RS2008ConfigurationManager%5B8%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="RS2008ConfigurationManager" border="0" alt="RS2008ConfigurationManager" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S32yTlr8qoI/AAAAAAAAAE0/Q4w5IT4hxM4/RS2008ConfigurationManager_thumb%5B5%5D.png?imgmax=800" width="240" height="181" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;To create the subscription you need to use the Report Manager (to gain access to this you can right mouse click on the report folder within the team explorer): &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32yT-ZVJcI/AAAAAAAAAE4/7v9N0vdgJ1Y/s1600-h/TE2010ReportSite%5B7%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="TE2010ReportSite" border="0" alt="TE2010ReportSite" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S32yUljqjpI/AAAAAAAAAE8/LXMSY-VUokg/TE2010ReportSite_thumb%5B5%5D.png?imgmax=800" width="203" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Once the report manager has loaded at the root folder, for your team project report folder, with a list of reports and folders. Then click on the Sprint Burndown report to view the report. After the report has rendered select the subscriptions tab, when the page has loaded, click on New Subscriptions. &lt;/p&gt;  &lt;p&gt;Then complete the necessary details on how and when the report should be delivered.&amp;#160; If your team project has only one work stream then all the report parameters can bet set to use the report defaults.&amp;#160; Otherwise set the value of the release and workstream parameter that you require and the remaining parameters can be left set to use the report defaults: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S32yVVJCN2I/AAAAAAAAAFA/g04MpxLtCUk/s1600-h/SprintBurnDownReportParameters%5B6%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="SprintBurnDownReportParameters" border="0" alt="SprintBurnDownReportParameters" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S32yWImEwaI/AAAAAAAAAFE/IOwRaWzwy3g/SprintBurnDownReportParameters_thumb%5B4%5D.png?imgmax=800" width="240" height="148" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;When there is only one work stream the report can work out the release and work stream and then current sprint.&amp;#160; When there is multiple work streams by default the report will get the current release but then default to the first work stream and work out the current sprint for the work stream.&amp;#160; To get the sprint burndown for the other work streams repeat the steps to create a new subscription and select the required release and work stream.&amp;#160; After the release has finished the subscription for the multiple work streams, it will need to be updated to the next release and work streams.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-708020054578723890?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/708020054578723890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=708020054578723890' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/708020054578723890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/708020054578723890'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/01/how-to-emailing-sprint-burndown-report.html' title='How To: Emailing the Sprint Burndown report'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_CJNik6Tu6JU/S32yTlr8qoI/AAAAAAAAAE0/Q4w5IT4hxM4/s72-c/RS2008ConfigurationManager_thumb%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-2256871562694772373</id><published>2009-12-09T21:26:00.000Z</published><updated>2010-02-18T21:27:59.451Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Builds'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>My Adventures in Codeplex</title><content type='html'>&lt;p&gt;In October 2009 I created 2 codeplex projects which I would to tell you about: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://ssrsmsbuildtasks.codeplex.com/" mce_href="http://ssrsmsbuildtasks.codeplex.com/"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;SQL Server Reporting Services MSBuild Tasks (ssrsmsbuildtasks)&lt;/h4&gt;  &lt;p&gt;A few years ago I created some tasks for MSBuild to help deploy reports for my project, details can be found &lt;a href="http://zogamorph.blogspot.com/2006/12/delpoying-reporting-services-reports.html" target="_blank"&gt;here&lt;/a&gt;,&amp;#160; since then my tasks have been re-used in a few other projects within my company.&amp;#160; However lately we have been doing a few projects which have made use of Reporting Services integrated mode with SharePoint, which meant that my tasks were unusable as they only work with a native mode report server. &lt;/p&gt;  &lt;p&gt;So I have been updating them to include support for an integrated mode report server.&amp;#160; Also before I added the integrated mode support I took some time to rewrite my original native mode tasks as well.&amp;#160; The re-writing of the tasks includes some improved understanding of MSBuild by making more use of Item Groups and metadata for setting of report server properties of the report items being deployed.&amp;#160; &lt;/p&gt;  &lt;p&gt;I placed the tasks within codeplex as I needed a better way of sharing my tasks other than through the blog post.&amp;#160; Also using the task is helpful in getting the your reporting project integrated with any continuous build of your project.&amp;#160; Another way they can help is with automating unit testing of your reporting project which I have talked about how to do from a previous &lt;a href="http://zogamorph.blogspot.com/2009/08/unit-testing-report-within-reporting.html" target="_blank"&gt;post&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;The SQL Server Reporting Services MSBuild Tasks are available from the following URL: &lt;a title="http://ssrsmsbuildtasks.codeplex.com/" href="http://ssrsmsbuildtasks.codeplex.com/" target="_blank" mce_href="http://ssrsmsbuildtasks.codeplex.com/"&gt;http://ssrsmsbuildtasks.codeplex.com/&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Server Reporting Services Slide Shower (ssrsslideshower)&lt;/h4&gt;  &lt;p&gt;While working on our Scrum for Team System process templates for Team Foundation Server (&lt;a title="http://www.scrumforteamsystem.com" href="http://www.scrumforteamsystem.com/" target="_blank" mce_href="http://www.scrumforteamsystem.com"&gt;http://www.scrumforteamsystem.com&lt;/a&gt;) I created a useful tool.&amp;#160; The tool helps to show reports that are important to a scrum team in a sort slide show presentation, more details can be found through this previous &lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-report-slide-show.html" target="_blank"&gt;post&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;While writing the tool most of the mechanics of the tool doesn’t depend on Team Foundation Server or our Scrum template.&amp;#160; Also I thought it would be a useful tool for people who wish to demo any reports that are within their reporting services infrastructure.&amp;#160; So I have removed the dependences of Team Foundation Server and our Scrum Template.&amp;#160; &lt;/p&gt;  &lt;p&gt;I have plans to improve the tool, within my limits of coding knowledge, to allow reports parameters values or labels to be set as it renders the reports within the slide show. I also plan to get it working with a integrated report server as well.&amp;#160; However my ssrsmsbuildtasks project has taken most of my time but over the next few week I plan to start making my changes to this project. &lt;/p&gt;  &lt;p&gt;I placed the project on codeplex because within our Scrum for Team System V3 template for Team Foundation Server 2010, which beta 2 is now available from this &lt;a href="http://scrumforteamsystem.com/cs/forums/4554/ShowPost.aspx" target="_blank" mce_href="http://scrumforteamsystem.com/cs/forums/4554/ShowPost.aspx"&gt;link&lt;/a&gt;,&amp;#160; we have dropped the inclusion of this tool and plan to release it within codeplex.&amp;#160; This is&amp;#160; mainly because it was a value add tool and not needed as part of the process template. Also the changes that were made to template and the reports, which now don’t have clear defaults for our report parameters which fit into the my improvements plans that I mention above.&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;The SQL Server Reporting Services Slide Shower is available from the following URL: &lt;a title="http://ssrsslideshower.codeplex.com/" href="http://ssrsslideshower.codeplex.com/" target="_blank" mce_href="http://ssrsslideshower.codeplex.com/"&gt;http://ssrsslideshower.codeplex.com/&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-2256871562694772373?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/2256871562694772373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=2256871562694772373' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2256871562694772373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2256871562694772373'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/12/my-adventures-in-codeplex.html' title='My Adventures in Codeplex'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-627828368038055295</id><published>2009-12-07T21:19:00.000Z</published><updated>2010-02-18T21:21:43.960Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='TFS2010'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v3'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><title type='text'>SfTS V3 Beta 2:Helping to see the wood for the trees</title><content type='html'>&lt;p&gt;Within any application lifetime management methodology, the reports are a useful tool to help see how well , or not , the project is progressing.&amp;#160; Within the Scrum methodology the reports which are used for tracking progress are the burndown reports.&amp;#160; In the Scrum for Team Systems process templates for Team Foundation Server these reports are available to help with managing the project.&amp;#160; &lt;/p&gt;  &lt;p&gt;With a manual run burndown report when an unexpected trend in the burndown happens, there is an option to manually add an annotation.&amp;#160; This would help during a retrospective when talking about why the trend oddity occurred.&amp;#160; Within our previous versions of the Scrum for Team System templates our burndown reports would only show the end of each days aggregated totals.&amp;#160; Any unexpected totals would have to investigated to understand the underlying cause.&amp;#160; Previously this would have involved either using Team Foundation Explorer to review the history and comments; Using Excel Pivot Services to query the data or writing a report against the warehouse. This can take some time to create and analyse the result set.&amp;#160; &lt;/p&gt;  &lt;p&gt;In connection with the above for the last few months I, with the help of fellow work colleague &lt;a href="http://blogs.conchango.com/kathrynbegley/"&gt;Kate Begley&lt;/a&gt;, have been working on writing the reports for the Scrum for Team System V3 process template (For which Beta 2 has been released and details are available from &lt;a href="http://www.scrumforteamsystem.com/cs/forums/4554/ShowPost.aspx"&gt;here&lt;/a&gt;) part of which has been adding drill-though report functionality to the reports.&amp;#160; This helps with the investigation in explaining for example why there was an unexpected up trend in our sprint burndown seen in our report below: &lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S32vVuBgMSI/AAAAAAAAAEY/vnhlicLrcUU/s1600-h/BurnDownChart%5B5%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="BurnDownChart" border="0" alt="BurnDownChart" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S32vWCnZIkI/AAAAAAAAAEc/8SE4IiFfTcQ/BurnDownChart_thumb%5B3%5D.png?imgmax=800" width="240" height="189" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;To get drill-though details for the end of day click on any data point for example within the blue circle in the image above, the drill though details report will be displayed as seen below: &lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://lh3.ggpht.com/_CJNik6Tu6JU/S32vXD9FKqI/AAAAAAAAAEg/JZnnDK4lnm8/s1600-h/BurnDownDayView%5B7%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="BurnDownDayView" border="0" alt="BurnDownDayView" src="http://lh5.ggpht.com/_CJNik6Tu6JU/S32vX50AXiI/AAAAAAAAAEk/eoj6fV5DqJc/BurnDownDayView_thumb%5B5%5D.png?imgmax=800" width="240" height="225" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;In this example the details report shows the work items broken down by the incomplete tasks which contribute to the sprint burndown line aggregated daily totals, complete tasks which have been completed up to that day, and the tasks that have been descoped within the selected sprint / team.&amp;#160; The incomplete tasks are further grouped together by their states showing the subtotals for each state, as well as the grand total of incomplete tasks, which are used to make up the burndown trend. &lt;/p&gt;  &lt;p&gt;To investigate the unexpected up trend in our sprint burndown I would need to compare the totals with the totals of the previous day. To do that I would export to excel the details report of the day concerned and the previous days details and compare these side by side to analyse the up trend, as shown below:&lt;/p&gt;  &lt;p align="left"&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32vYxW176I/AAAAAAAAAEo/NGyEEi6OL1w/s1600-h/ExeclSidebySide%5B6%5D.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="ExeclSidebySide" border="0" alt="ExeclSidebySide" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S32vZvhuZ0I/AAAAAAAAAEs/mwWuyAEh1oo/ExeclSidebySide_thumb%5B4%5D.png?imgmax=800" width="216" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The above shows the reason for the up trend in this example was due to new work being added to the sprint. Please keep in mind this might not always be the case as other outcomes could of happened: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;New tasks could have been added and the incomplete task could have had the work remaining total for it adjusted upward because of unexpected issues &lt;/li&gt;    &lt;li&gt;Both the currently incomplete tasks could have had the work remaining adjusted upward because of impediments &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Other reports in beta 2 which have the drill-through functionality are: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;QA / Bug History Chart &lt;/li&gt;    &lt;li&gt;Release / Product Burndown Chart by Day &lt;/li&gt;    &lt;li&gt;Release / Product Cumulative Flow &lt;/li&gt;    &lt;li&gt;Sprint / Sprint Burndown Chart &lt;/li&gt;    &lt;li&gt;Sprint / Sprint Cumulative Flow &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-627828368038055295?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/627828368038055295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=627828368038055295' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/627828368038055295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/627828368038055295'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/12/sfts-v3-beta-2helping-to-see-wood-for.html' title='SfTS V3 Beta 2:Helping to see the wood for the trees'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_CJNik6Tu6JU/S32vWCnZIkI/AAAAAAAAAEc/8SE4IiFfTcQ/s72-c/BurnDownChart_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-2648459698671836596</id><published>2009-08-27T22:13:00.000+01:00</published><updated>2010-02-18T21:15:08.840Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='DTS'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Unit Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Unit Testing Report within Reporting Services: My Theory</title><content type='html'>&lt;p&gt;I have been working with Microsoft SQL Server Reporting Services, since its first release, within many of my projects.&amp;#160; One of the biggest tasks, that I find with writing a report is the testing the reports and making sure the data that is displayed is correct.&amp;#160; My method of developing and testing reports is as follows:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Write the queries, outside Reporting Services, for creating the report data set(s) with the parameters defined which will be configured within the report.      &lt;ul&gt;       &lt;li&gt;Define the parameters that report data set would create and assign a valid value. &lt;/li&gt;        &lt;li&gt;Execute the queries. &lt;/li&gt;        &lt;li&gt;Inspect the results to make sure that they meet the expected results. &lt;/li&gt;        &lt;li&gt;Repeat with a new valid value or fix any issues. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;After one or two or even three passes that have worked then I take the queries and put them into report data sets. &lt;/li&gt;    &lt;li&gt;Then I define the report layout. &lt;/li&gt;    &lt;li&gt;Then I preview the report make sure it’s still correct &lt;/li&gt;    &lt;li&gt;Then I release to our testers for testing. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;With this amount of manual testing there could be a potential for mistakes to creep past for several reasons: The test data often isn’t diverse enough to test all the logic of the queries; The report data has a lot of rows which aren’t all inspected; Run out of time as the testing was under estimated so amount of testing is reduced.&lt;/p&gt;  &lt;p&gt;I did, at the beginning of last year (2008), look into away of being able to test the reports by an automated tool.&amp;#160; I was looking for a way to compare the information that the report was displaying and compare it to some expected results.&amp;#160; The need to test the report itself and not just the underlying queries were for the following reasons:&lt;/p&gt;  &lt;p&gt;General Reasons: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The Report could be doing more data manipulation outside the SQL queries that have been unit tested.      &lt;ul&gt;       &lt;li&gt;Embedded reporting calculations &lt;/li&gt;        &lt;li&gt;Embedded VB.Net code &lt;/li&gt;        &lt;li&gt;External class libraries code &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;(all of the above could have been unit tested separately but still could produce incorrect information if wired-up incorrectly) &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Test visibility setting for sections of the reports. &lt;/li&gt;    &lt;li&gt;Test any embedded report calculations &lt;/li&gt;    &lt;li&gt;The Report could be using MDX and there isn’t an easy unit testing frame work for MDX &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;My Project Reasons: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;All the reports used embedded SQL and MDX. &lt;/li&gt;    &lt;li&gt;Writing reports against a 3rd party data warehouse and processes &lt;/li&gt;    &lt;li&gt;There is no database project in which to use a unit test frame work for SQL. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Searching the internet I came across this article: &lt;a href="http://msdn.microsoft.com/en-us/library/aa964139(SQL.90).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa964139(SQL.90).aspx"&gt;Using Visual Studio 2005 to Perform Load Testing on a SQL Server 2005 Reporting Services Report Server&lt;/a&gt;, which gives a guide on how to stress test reports.&amp;#160; This is helpful to ensure that the reporting solution/architecture can handle the demands that are placed upon it.&amp;#160; I also thought that this method of testing can be used for 2 other forms of testing:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Simple unit testing: Ensure that report can render.&amp;#160; Placing this within a build process, that adds data into the reported database, then runs the web test to check if the report renders can help highlight if there have been changes to the database that breaks the build.&amp;#160;&amp;#160; This can happen if the reports are based off some application database for simple reporting and the database is using an ORM tool. (Which at least one of our projects is doing). &lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt;   &lt;li&gt;Build verification testing: Does the report render? Running a web test after the deployment has happened would highlight any error in the deployment of the solution or deployment of the infrastructure. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I helped to get this method of testing implemented for the above mentioned reason for an application project, where it did help to capture and highlight builds that broke the reports. However as this didn’t meet the requirements fully I was looking as this method, which uses web tests, of testing as it was only inspecting the http responses. &lt;/p&gt;  &lt;p&gt;It wasn’t until recently that I starting looking again at unit testing reports again because of my current project as testing the reports is one of the hardest jobs for the following reason: Developing reports based upon a platform so have no control of the flow of the data.&amp;#160; So I looked again at the beginning of this year (2009) and again didn’t found much there that would help me.&amp;#160; So I went to the drawing board to design my own approach and remember that in June 2008 I used Reporting Services in interesting way; I wrote a report which was only create to generate an dynamic XML document for a web page to consume and bind the data to another control (more information can be found here: &lt;a href="http://zogamorph.blogspot.com/2008/06/could-http-soap-t-sql-endpoint-be.html" target="_blank"&gt;Could HTTP Soap / T-SQL endpoint be replaced by Reporting Services XML Reports?&lt;/a&gt; ).&amp;#160; So I took a further look into the XML render options, to see how the reports that uses chart would render into XML, which my current project heavily utilises, and found that all the values of the data points within the charts were exposed.&amp;#160; This meant that I could test the reports in the way that I intended.&amp;#160; &lt;/p&gt;  &lt;p&gt;My next challenge was to design the process that would render the report into XML and then perform some sort of test.&amp;#160; The test was easy, if the report was going to produce an XML document then I should be able determine the how the report will render the XML based upon the following: Expected results based upon the known set of data within data store that report is querying; Passing known values for the reports and knowing the XML setting for the reports; So I decided to do a comparison on the report XML against a prepared XML document.&amp;#160; The next problem was how to do the comparison as there wasn’t a tool that I could find. So I asked a few of my more .NET savvy guys as well with no joy.&amp;#160; &lt;/p&gt;  &lt;p&gt;Then I remembered that SQL Server Integration Services (SSIS) has an XML task that does a XML Compare that compares the element’s attributes and more importantly the values.&amp;#160; So I set about creating a SSIS package to do the following: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Loop though a control file that contains the location of the reports to test; required parameters, values and location of the expect XML output. &lt;/li&gt;    &lt;li&gt;Download the reports into XML format from the Report Server. &lt;/li&gt;    &lt;li&gt;Then use the XML task to compare the results from the report server and compared against the expect results. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Based on some initial testing of this approach work for testing my reports the results were good.&amp;#160; However I haven’t been able to fully implement my approach for the following reasons:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Need to work on creating the test data for project. &lt;/li&gt;    &lt;li&gt;Need to work on getting the test data through the 3rd party process. &lt;/li&gt;    &lt;li&gt;Need to work out how to deal with time as many of my reports show time differently. &lt;/li&gt;    &lt;li&gt;Need to work out how make it part of the build/test process. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Also recently I have found that my approach is similar to a tool that is available to buy from &lt;a href="http://www.innosphere.ca/Products/SSRSUnitTestingSuite/tabid/110/Default.aspx" mce_href="http://www.innosphere.ca/Products/SSRSUnitTestingSuite/tabid/110/Default.aspx"&gt;Innosphere&lt;/a&gt;.&amp;#160; &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-2648459698671836596?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/2648459698671836596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=2648459698671836596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2648459698671836596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2648459698671836596'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/08/unit-testing-report-within-reporting.html' title='Unit Testing Report within Reporting Services: My Theory'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-8061215984079268746</id><published>2009-08-03T21:01:00.003+01:00</published><updated>2010-02-18T21:08:31.787Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='TFS2010'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v3'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><title type='text'>SfTS V3: The Beta 1 reports new comers</title><content type='html'>As mentioned in my previous blog post, there are some new reports available in the Scrum for Team System V3 Beta 1 Template. I would like to give a high level overview of the new reports as there will be full report guidance available with the template explaining in more detail how to use the reports. &lt;br /&gt;The new Diagnostic report isn’t really a new report, more of a spin off from another report. Version 2.x included a Version report that provided details about the status of the Team Foundation Server warehouse process. This covered information like: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;When the process last ran &lt;/li&gt;&lt;li&gt;When the process finished loading data into the warehouse &lt;/li&gt;&lt;li&gt;How often the warehouse process would run &lt;/li&gt;&lt;li&gt;When the last time the cube was changed &lt;/li&gt;&lt;/ul&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32qrrCOk4I/AAAAAAAAAD4/kJ4IM1Gl_Rg/s1600-h/Version2xReport%5B9%5D.png" target="_blank"&gt;&lt;img alt="Version2xReport" border="0" height="240" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S32qsmkLJKI/AAAAAAAAAD8/TX29oC6pIfE/Version2xReport_thumb%5B7%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Version2xReport" width="205" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Team Foundation Server 2010 provides more information about the Team Foundation Server warehouse process, including: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is the warehouse blocked from running &lt;/li&gt;&lt;li&gt;Is the OLAP processing blocked from running &lt;/li&gt;&lt;li&gt;The last full process started and ended time &lt;/li&gt;&lt;li&gt;The last incremental process started and ended time &lt;/li&gt;&lt;/ul&gt;&lt;a href="http://lh3.ggpht.com/_CJNik6Tu6JU/S32qtYdkGCI/AAAAAAAAAEA/biwaNJxutnA/s1600-h/WarehouseReport%5B7%5D.png" target="_blank"&gt;&lt;img alt="WarehouseReport" border="0" height="180" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S32quPLmpnI/AAAAAAAAAEE/9x0CNHWjPq4/WarehouseReport_thumb%5B5%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="WarehouseReport" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;As there was more information available we split the report out so it was less cluttered and easier to read. The Diagnostic report is really useful for investigating reporting issues such as reports showing out of date data. &lt;br /&gt;The Sprint Team Aggregate report, which is new to version 3, is like a classic Sprint burndown, meaning that it shows the burndown of the Sprint Backlog Task, however the report will separately plot each selected team within the selected Sprint. There is also the option to show an aggregated total of the selected teams. This will give a comparison between how well the teams are working. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh3.ggpht.com/_CJNik6Tu6JU/S32qvMNNJmI/AAAAAAAAAEI/rgstkRvkECE/s1600-h/SprintTeamAggregate%5B6%5D.png" target="_blank"&gt;&lt;img alt="SprintTeamAggregate" border="0" height="188" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S32qvg1DVgI/AAAAAAAAAEM/5QAa88H6HJM/SprintTeamAggregate_thumb%5B4%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="SprintTeamAggregate" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;The final, and saving the best till last, new report is the “Sprint Burndown – Tasks and Stories” report which provides a comparative view of story versus task work burndown at a Sprint or team level.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S32qwialqrI/AAAAAAAAAEQ/MTHVxWgjW84/s1600-h/SprintBurnDownTaskStories%5B5%5D.png" target="_blank"&gt;&lt;img alt="SprintBurnDownTaskStories" border="0" height="177" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S32qxKASllI/AAAAAAAAAEU/V8jbkN8Q7Qo/SprintBurnDownTaskStories_thumb%5B3%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="SprintBurnDownTaskStories" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;This is based upon some of the experiences from our agile coaches and other Scrum teams, about what the Sprint burndown should be focusing on: getting Product Backlog “Done”.. So this report shows how many story points have been burnt down as well as the traditional view of the Task burndown.&lt;br /&gt;&lt;br /&gt;One of the issues that this report can show is how healthy the task burn down actually is within the sprint. The team(s) could be completing tasks but they are not helping to towards the completion of stories which can highlight quality issues and too much work in progress. Another use for this report is to highlight if the Product Backlog items have been correctly sized or Sprint Backlog Tasks have broken down correctly according to the size of the associated Product Backlog Item.&lt;br /&gt;&lt;br /&gt;This report is also our first report that is making use of the Reporting Services 2008 enhanced charting features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-8061215984079268746?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/8061215984079268746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=8061215984079268746' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8061215984079268746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8061215984079268746'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/sfts-v3-beta-1-reports-new-comers.html' title='SfTS V3: The Beta 1 reports new comers'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_CJNik6Tu6JU/S32qsmkLJKI/AAAAAAAAAD8/TX29oC6pIfE/s72-c/Version2xReport_thumb%5B7%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-8616961404119820506</id><published>2009-07-29T21:38:00.005+01:00</published><updated>2010-02-18T21:10:04.684Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='TFS2010'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v3'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><title type='text'>SfTS V3 Operation: Reports face lift.</title><content type='html'>For the last few months I, with the help of fellow work colleague &lt;a href="http://blogs.conchango.com/kathrynbegley/" mce_href="http://blogs.conchango.com/kathrynbegley/" target="_blank"&gt;Kate Begley&lt;/a&gt;, have been working on the writing the reports for the Scrum for Team System V3 process template, which Beta 1 has been released and details are available from &lt;a href="http://blogs.conchango.com/sfts/archive/2009/07/28/scrum-for-team-system-v3-beta-programme.aspx" mce_href="http://blogs.conchango.com/sfts/archive/2009/07/28/scrum-for-team-system-v3-beta-programme.aspx"&gt;http://blogs.conchango.com/sfts/archive/2009/07/28/scrum-for-team-system-v3-beta-programme.aspx&lt;/a&gt;.   &lt;br /&gt;&lt;br /&gt;There are a number of changes, from a reporting aspect, that have been introduced into Team Foundation Server 2010 platform and the Scrum for Team System V3 process template like: Warehouse schema changes; only supporting Reporting Services 2008; a sophisticated multi-team support model and new QA model. As a result the reports have been completely rewritten so there is a limited number in this beta release.   &lt;br /&gt;However I would like to highlight some of the smaller updates that been applied to the reports to help readability / usability of the reports which are as follows:   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;A reporting site folder structure has been created to make browsing the reports easier &lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Reporting tool tips on the charts to display the unit, value, date that point on the chart is showing. &lt;/li&gt;&lt;/ul&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32lkWc3t_I/AAAAAAAAADQ/bBLj9iEiNcA/s1600-h/ToolTips%5B8%5D.png" target="_blank"&gt;&lt;img alt="ToolTips" border="0" height="155" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S32lk-IjRkI/AAAAAAAAADU/XcvLBqGZEqU/ToolTips_thumb%5B6%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="ToolTips" width="240" /&gt;&lt;/a&gt;   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Today strip line, with tool tip showing where Today is. &lt;/li&gt;&lt;/ul&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S32llceNfTI/AAAAAAAAADY/n83Kix-hI_Q/s1600-h/TodayWithHelp%5B9%5D.png" target="_blank"&gt;&lt;img alt="TodayWithHelp" border="0" height="161" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S32llwA5w0I/AAAAAAAAADc/yLzncrHlijI/TodayWithHelp_thumb%5B7%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="TodayWithHelp" width="240" /&gt;&lt;/a&gt;   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Small descriptions have been embedded into the reports so when viewing the report in Report Manager or Team Foundation Server Web access their descriptions can be seen to give a snapshot of their function. &lt;/li&gt;&lt;/ul&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32lmogey_I/AAAAAAAAADg/thGa9iZaZ6U/s1600-h/TFSWebView%5B14%5D.png" target="_blank"&gt;&lt;img alt="TFSWebView" border="0" height="62" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S32lnKlJUxI/AAAAAAAAADk/AKjmV2UYk6M/TFSWebView_thumb%5B10%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="TFSWebView" width="240" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S32lnitWSJI/AAAAAAAAADo/mEU0VfT6aI4/s1600-h/ReportManagerVeiw%5B8%5D.png" target="_blank"&gt;&lt;img alt="ReportManagerVeiw" border="0" height="67" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S32loWAh-VI/AAAAAAAAADs/OMWGZVgH8Sw/ReportManagerVeiw_thumb%5B4%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="ReportManagerVeiw" width="240" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A report footer has been added with the same embedded description and link to a report guidance (which will be coming soon). &lt;/li&gt;&lt;/ul&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S32loiSpfPI/AAAAAAAAADw/i7fYt0a27_E/s1600-h/ReportFooter%5B7%5D.png" target="_blank"&gt;&lt;img alt="ReportFooter" border="0" height="36" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S32lpEd884I/AAAAAAAAAD0/PoELAspQ-kY/ReportFooter_thumb%5B5%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="ReportFooter" width="240" /&gt;&lt;/a&gt;   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Portal reports can be resized within the SharePoint portal by changing the height and width report parameters to help with customising the SharePoint portal. &lt;/li&gt;&lt;/ul&gt;The reports that are still available from previous versions are as follows:   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Version – Diagnostic &lt;/li&gt;&lt;li&gt;Bug History Chart – QA &lt;/li&gt;&lt;li&gt;Product Burndown Chart By Day – Release &lt;/li&gt;&lt;li&gt;Product Cumulative Flow – Release &lt;/li&gt;&lt;li&gt;Sprint Burndown Chart – Sprint &lt;/li&gt;&lt;li&gt;Sprint Cumulative Flow – Sprint &lt;/li&gt;&lt;/ul&gt;Alongside these additional new reports for version 3, which I will cover in another &lt;a href="http://zogamorph.blogspot.com/2010/02/sfts-v3-beta-1-reports-new-comers.html" mce_href="http://blogs.conchango.com/stevewright/archive/2009/08/03/sfts-v3-the-beta-1-reports-new-comers.aspx" target="_blank"&gt;blog&lt;/a&gt;:   &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Warehouse Status - Diagnostic &lt;/li&gt;&lt;li&gt;Sprint Burndown - Tasks and Stories Chart – Sprint &lt;/li&gt;&lt;li&gt;Sprint Team Aggregate – Sprint &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-8616961404119820506?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/8616961404119820506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=8616961404119820506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8616961404119820506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8616961404119820506'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/07/sfts-v3-operation-reports-face-lift.html' title='SfTS V3 Operation: Reports face lift.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_CJNik6Tu6JU/S32lk-IjRkI/AAAAAAAAADU/XcvLBqGZEqU/s72-c/ToolTips_thumb%5B6%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-2386077394010617774</id><published>2009-03-30T23:26:00.000+01:00</published><updated>2010-02-17T22:29:21.884Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v2'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Reporting Services 2008 Report automatic upgrade gotcha.</title><content type='html'>&lt;p&gt;For the Scrum for Team System project I have been focusing on the reports; I came across an issue which was due to the way the Reporting Services 2008 &amp;quot;automatic upgrade&amp;quot; feature upgraded our reports.&lt;/p&gt;  &lt;p&gt;The Scrum for Team System template contains over 20 reports all written for Reporting Services 2005. This was done because Team Foundation Server 2008 only worked on SQL Server 2005 and Reporting Services 2005. Then in August of 2008 Team Foundation Server 2008 Services Pack 1 was released which added support for the Team Foundation Server 2008 is to run on SQL Server 2008 platform.&lt;/p&gt;  &lt;p&gt;With Reporting Services 2008 there is a new reporting definition language schema. However reporting services does have backward compatibility method as describe below: &lt;/p&gt;  &lt;p&gt;The report server will validate report definition file against the included reference to the RDL namespace which specifies the version of the report definition schema that is used. &lt;/p&gt;  &lt;p&gt;The report is automatically upgraded the first time it is viewed, but the stored report definition file remains unchanged. &lt;/p&gt;  &lt;p&gt;So if you edit the report from the server it will still remain in old schema and not the new schema.&lt;/p&gt;  &lt;p&gt;To get automatically upgraded report definition you will open the report in one of the authoring tools: Business Intelligence Development Studio (BIDS) or Microsoft Report Builder 2.0.&lt;/p&gt;  &lt;p&gt;So I did some testing to see how the 2005 reports would look after the reporting services 2008 processing. I found that 2 reports didn’t render the same as did on reporting services 2005. The 2 reports had a common layout they were using a reporting services sleazy hack: The Green-Bar Matrix. The cell which controls the background colour was a lot more visible than the original as well as the text. So I rewrote the reports and were released them with version 2.2. &lt;/p&gt;  &lt;p&gt;Then one of our template users reported that one of the other reports stopped working. The report started to give the following error: &lt;/p&gt;  &lt;p&gt;&lt;i&gt;The processing of Parent for the tablix ‘table1’ cannot be performed. The comparison failed. Please check the data type returned by the Parent.&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;I was able to trace the error to an option in one of the report define groups: Recursive parent, which can found under advanced; removing the option made the report worked again. I haven’t been able trace why the error happens it only seems when our data came back in a certain way which I am currently looking into.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-2386077394010617774?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/2386077394010617774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=2386077394010617774' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2386077394010617774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2386077394010617774'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/03/reporting-services-2008-report.html' title='Reporting Services 2008 Report automatic upgrade gotcha.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3244511830436075714</id><published>2009-03-30T23:18:00.000+01:00</published><updated>2010-02-17T22:20:39.312Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Geo Spatial'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Geometry'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Some practical SQL Spatial tips.</title><content type='html'>&lt;p&gt;I have just finished a project were I made a lot of use of the SQL Spatial to do some processing and loading into the database. Here are some of lesson I learnt:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The first method that needs to call after instantiating a SQLGeographybuilder object is: SetSrid() then the BeginGeography(), BeginPoint(). &lt;/li&gt;    &lt;li&gt;Before using sending a SQLGeometry object to the SQL Server use the IsVaild() function to ensure that Geometry object is valid.      &lt;p&gt;I create a console application which loaded line, which was using OS coordinates system, data from a flat file. Some of the line data within the file wasn’t as correct as I was led to believe. The application create the SQLGeometry object .NET but the Sql Server then rasied the error when it received and try to save it into the table. &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;The STPointN() function is 1 base which is stated in the Books On-Line &lt;/li&gt;    &lt;li&gt;If your query needs to select some of the derive data from the functions you can help performance by using persisted compute columns on the base table.      &lt;p&gt;I had to create a view which needed the latitude and longitude of the starting and end points of the geom line also including the distance. The view would take about 20 seconds to finish executing. Once I created some persisted compute columns on the base table the view would finish executing under 3 seconds &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;You can create more than one spatial index for a spatial column. &lt;/li&gt;    &lt;li&gt;Trying to join tables using the spatial functions isn’t great for performance. &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3244511830436075714?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3244511830436075714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3244511830436075714' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3244511830436075714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3244511830436075714'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/03/some-practical-sql-spatial-tips.html' title='Some practical SQL Spatial tips.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-1483599004068775891</id><published>2009-03-01T22:10:00.002Z</published><updated>2010-02-17T22:16:29.778Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Working With Reporting Services Multiple Value Parameters</title><content type='html'>A couple of colleagues of mine were working on a complicated reporting services project; they had one report which had a parameter which allowed a user to select multiple values of numbers, the problem they were facing was how pass the selected values into the query.&lt;br /&gt;&lt;br /&gt;They were looking for a way within SQL Server to split a string by a delimiter. As they were using a stored procedure to access the data and multiple value parameters, regardless of parameter type, are passed in as a string of comma separated values.&lt;br /&gt;&lt;br /&gt;One thing which they weren’t aware of was that with a multiple value parameter, the behaviour can differ between how the data is being retrieved i.e.: stored procedure or embed sql statement.&lt;br /&gt;If the data set is using direct query to gather the data then the multi value parameter can be used in the query with a IN clause like so: &lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Where&lt;/span&gt; column1 &lt;span class="kwrd"&gt;in&lt;/span&gt; (@pMultiValueParam)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;What happens is that before the query is sent to the SQL Server the query the report server substitutes the @pMulitValueParam with a comma separated list which makes it valid in clause like so: &lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Where&lt;/span&gt; column1 &lt;span class="kwrd"&gt;in&lt;/span&gt; (10, 3, 4, 56)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Also it has been blogged (&lt;a href="http://www.socha.com/blogs/john/2009/03/tfs-report-issues-with-sql-server-2008.html" mce_href="http://www.socha.com/blogs/john/2009/03/tfs-report-issues-with-sql-server-2008.html"&gt;http://www.socha.com/blogs/john/2009/03/tfs-report-issues-with-sql-server-2008.html&lt;/a&gt;) that in reporting services 2008 there is a new change in the behaviour. You could see the following message when you have no values to select:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Incorrect syntax near ')'.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When there are no values to pass, Reporting Services 2008 simply removes @pMultiValueParam, so you get something like "&lt;code&gt;Where column1 in ()"&lt;/code&gt; preventing this query from running. &lt;br /&gt;&lt;br /&gt;The solution is to add an expression to the pMultiValueParam report parameter. The expression is evaluated in order to determine what is passed to the query. &lt;br /&gt;&lt;br /&gt;Like so: &lt;br /&gt;&lt;br /&gt;&lt;code&gt;=IIF(Parameters! pMultiValueParam.Count &amp;gt; 0, Parameters!pMultiValueParam.Value, "")&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-1483599004068775891?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/1483599004068775891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=1483599004068775891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1483599004068775891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1483599004068775891'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/03/working-with-reporting-services.html' title='Working With Reporting Services Multiple Value Parameters'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3677380681867408690</id><published>2009-01-23T21:58:00.003Z</published><updated>2010-02-17T22:05:14.695Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Geo Spatial'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Geometry'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.Net'/><title type='text'>How to load spatial data into SQL Server 2008 from .Net</title><content type='html'>I have been working on a project which made use of the spatial data type geography within SQL Server 2008.&lt;br /&gt;&lt;br /&gt;An issue that I had was how to load the geography data from a KML file into SQL Server 2008. Currently there is no out of the box tools to do this. There is a 3&lt;sup&gt;rd&lt;/sup&gt; party tool, Safe FME, which offer either their own tool or components which extend integration services. This was overkill for my issues as I only had to do it once.&lt;br /&gt;&lt;br /&gt;So I wrote a console application which parses the KML file to extract the point data convert it to a SqlGeography type and store it in the database.&lt;br /&gt;&lt;br /&gt;To use the SqlGeography C# type you need to add reference to the following name space: Microsoft.SqlServer.Types. This can be found in the following dll: Microsoft.SqlServer.Types.dll&lt;br /&gt;Then use the following code to create the c# sqlgeography type:&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;// use SqlGeographyBuilder to help create the SqlGeography type &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;SqlGeographyBuilder geographyBuilder = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlGeographyBuilder(); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt;[] longLat; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;SqlGeography geography; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;// gets the co-ordinates &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;XElement coOrdinates = element.Element(ns + &lt;span class="str"&gt;"Point"&lt;/span&gt;).Element(ns + &lt;span class="str"&gt;"coordinates"&lt;/span&gt;); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="rem"&gt;// set the Spatial Reference Identifiers that will used to create the point &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;geographyBuilder.SetSrid(4326); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="rem"&gt;// state what type of geography object that I to create &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;geographyBuilder.BeginGeography(OpenGisGeographyType.Point); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;longLat = coOrdinates.Value.Split(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[1] {&lt;span class="str"&gt;','&lt;/span&gt;}); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&lt;span class="rem"&gt;// add the frist figure lat long point &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;geographyBuilder.BeginFigure(Convert.ToDouble(longLat[1]), Convert.ToDouble(longLat[0])); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&lt;span class="rem"&gt;// close the figure and geography class &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;geographyBuilder.EndFigure(); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;geographyBuilder.EndGeography(); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;&lt;span class="rem"&gt;// get the geography builder to return the sqlgeography type &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;geography = geographyBuilder.ConstructedGeography; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; geography; &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;After creating the data type I then needed to write the code send the data to the SQL server which as follows:&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;// set the command text &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; sqlCommandText = &lt;span class="str"&gt;"insert into [dbo].[Location]([Location],[CoOrdinates]) Values(@pLocation,@pCoOrdinates)"&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;// create the command object and set which command type &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;SqlCommand sqlCommand = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand(sqlCommandText, sqlConnection); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;sqlCommand.CommandType = CommandType.Text; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="rem"&gt;// create and add the paramter for standard sql data type &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;sqlCommand.Parameters.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter(&lt;span class="str"&gt;"@pLocation"&lt;/span&gt;, name.Value)); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="rem"&gt;// create and add the paramter for sql geography data type &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="rem"&gt;// as I am using and system CLR type have to say what data type name the parameter is &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;sqlCommand.Parameters.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter(&lt;span class="str"&gt;"@pCoOrdinates"&lt;/span&gt;, geography) {UdtTypeName = &lt;span class="str"&gt;"Geography"&lt;/span&gt;}); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&lt;span class="rem"&gt;// execute the command &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;sqlCommand.ExecuteNonQuery(); &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Like the report viewer control the Microsoft.SqlServer.Types namespace is not installed with .Net. For the application to work on another computer, without having to install SQL server or their client tools, a Redistributable package would need to be installed.&lt;br /&gt;&lt;br /&gt;The SQL Server System CLR Types package contains the components implementing the new geometry, geography, and hierarchyid types in SQL Server 2008. This component can be installed separately from the server to allow client applications to use these types outside of the server.&lt;br /&gt;&lt;br /&gt;A version can be found here: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6C3E9EF-BA29-4A43-8D69-A2BED18FE73C&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6C3E9EF-BA29-4A43-8D69-A2BED18FE73C&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyId=C6C3E9EF-BA29-4A43-8D69-A2BED18FE73C&amp;amp;displaylang=en&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3677380681867408690?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3677380681867408690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3677380681867408690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3677380681867408690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3677380681867408690'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/01/how-to-load-spatial-data-into-sql.html' title='How to load spatial data into SQL Server 2008 from .Net'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3598277908371820897</id><published>2009-01-19T21:42:00.000Z</published><updated>2010-02-17T21:44:00.366Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Geo Spatial'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='Geometry'/><title type='text'>Business Intelligence with SQL Server 2008 Geometry Data Type.</title><content type='html'>&lt;p&gt;I am currently working on a project which is automating a business intelligence process base upon images and image recognition. The process is as follows:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Take a photography &lt;/li&gt;    &lt;li&gt;Put the photography through the image recognition software and record the recognition data. &lt;/li&gt;    &lt;li&gt;Process the recognition data into meaningful business metrics &lt;/li&gt;    &lt;li&gt;Produce a report on metrics &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The part of the process, from above, that I am helping with is processing the recognition data (the hit data) into meaningful business data. This process simply takes the hit data (which is a point), then creates some square blocks, which I use to group the hits data and perform some metric operations. The metrics currently use data about the area and the density of hits within the area. To help process this data I decided to make use of the SQL Server 2008 spatial type: Geometry.&lt;/p&gt;  &lt;p&gt;Firstly I would like to point out that I didn’t have to use the geometry type. As I am currently dealing with square areas, I can group or locate all the hits that fall within area by using the following filter clause: HitY between MinY and MaxY and HitX between MinX and MaxX. However by reading the filter alone can cause misunderstanding on what the filter is suppose to be doing. As I am using the geometry data type that filter is replaced by something which does state what the filter is doing, like so: area.STIntersects(HitPoint) = 1 with the added bonus of less code being written and read as well as less chance of a bug being created.&lt;/p&gt;  &lt;p&gt;Another point I would to make is that by using the geometry type my code is adaptable to changes. Currently our process is working to square areas and in the future that might change. Using the standard SQL filters that would mean all the filter clauses of the data would have to be updated. Also I would need to be more sophisticated, which could take a longer development and testing cycle which could increase the risk of issues. With the use of the geometry type, only the way that the area polygon is created would need to be updated which will help in reducing the development and testing cycle which interns reduces the risk of issues.&lt;/p&gt;  &lt;p&gt;Another benefit of having some of the data stored as the geometry spatial data type is that I was able to evaluate or debug the steps of the process far easier. This is due to the way that SQL Server Management Studio display spatial data as shown below. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xjG-a0pSI/AAAAAAAAADI/_vANGIRLWs0/s1600-h/SpatialGrid%5B7%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="SpatialGrid" border="0" alt="SpatialGrid" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xjHfiYKwI/AAAAAAAAADM/AaRjv_2rZSs/SpatialGrid_thumb%5B5%5D.jpg?imgmax=800" width="240" height="102" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3598277908371820897?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3598277908371820897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3598277908371820897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3598277908371820897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3598277908371820897'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2009/01/business-intelligence-with-sql-server.html' title='Business Intelligence with SQL Server 2008 Geometry Data Type.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_CJNik6Tu6JU/S3xjHfiYKwI/AAAAAAAAADM/AaRjv_2rZSs/s72-c/SpatialGrid_thumb%5B5%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-8534818103006242393</id><published>2008-10-16T22:05:00.003+01:00</published><updated>2010-02-17T21:36:22.251Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v2'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><title type='text'>Scrum for Team System Version 2.2 support for SQL Server 2008</title><content type='html'>As I have mention in a previous blog entry I’ve been heavily involved in the Scrum for Team System process template since the start of version 2 and have written the majority of the reports. I have faced, and still do, some challenges while doing this. Some of them have been around how to display the data within reporting services 2005. &lt;br /&gt;&lt;br /&gt;Now with the release of Team Foundation Server 2008 Service Pack 1, release in August, this enables Team Foundation Server 2008 to be used on a SQL Server 2008 environment. This will make some of reporting challenges I faced with reporting services 2005 disappear. This will due to major changes that been made to reporting services 2008 like Tablix control and wider Dundas chart controls.&lt;br /&gt;&lt;br /&gt;Within this release we have made a patch which will update some of the reports for reporting services 2008. This to fix some of the reporting services 2005 Patterns and Recipes which became visible. I am currently working looking at how Scrum for Team System can make more use of the reporting services 2008 which we will release as an advance reporting pack in the future. &lt;br /&gt;&lt;br /&gt;To find out more about the Scrum for Team System SQL Server 2008 patcher please read the following &lt;a href="http://blogs.conchango.com/sfts/archive/2008/10/15/scrum-for-team-system-sql-server-2008-patcher-user-guide.aspx"&gt;Scrum for Team System blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/new-reporting-features-available-in.html" target="_blank"&gt;New Reporting Features available in Scrum for Team System v2.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/build-reports-added-to-scrum-for-team.html" target="_blank"&gt;Build Reports added to Scrum for Team System v2.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-report-slide-show.html" target="_blank"&gt;The Scrum for Team System report slide show tool&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Scrum for Team System Version 2.2 support for SQL Server 2008&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-8534818103006242393?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/8534818103006242393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=8534818103006242393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8534818103006242393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/8534818103006242393'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-version-22.html' title='Scrum for Team System Version 2.2 support for SQL Server 2008'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-6318203692441732650</id><published>2008-10-14T22:08:00.002+01:00</published><updated>2010-02-17T21:35:50.641Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>The Scrum for Team System report slide show tool</title><content type='html'>As I have mention in another blog posts; I’ve been heavily involved in the Scrum for Team System process template since the start of version 2 and to coincide with the release of version 2.2; I would like bring your attention to a new tool, which I help to developed, that has been added to this release.&lt;br /&gt;&lt;br /&gt;I started creating this tool due to some feedback we got from our beta users for “&lt;a href="http://www.scrumforteamsystem.com/en/TaskBoardBeta/Default.aspx" mce_href="http://www.scrumforteamsystem.com/en/TaskBoardBeta/Default.aspx"&gt;TaskBoard for Team system&lt;/a&gt;” tool. The request was to add a demonstration mode into the application which would show things like swimming lane-view and the following reports: Sprint burndown chart; Sprint cumulative flow as these can be view within the application. &lt;br /&gt;&lt;br /&gt;The reason for the request was create the sense of: "Look guys, this is what we are working on, and this is how we are doing", throughout the day, not only during the scrum meetings. This also happen a lot within our projects which they do something similar as well. Another reason for the tool to separate from the Task Board application was to avoid polluting what the Task Board application was suppose to do. &lt;br /&gt;&lt;br /&gt;So a new page was added to ScrumforTeamSystem virtual folder called: ReportSlideShow. This will allow a selection of team system project(s) reports to be display by their parameters default values. However the reports don’t have to be scrum for team system only reports there is one caveat: all reports have to exist in all requested display projects.&lt;br /&gt;&lt;br /&gt;The report that are which are display is control by configuration file. To see how to figure which reports are display please use the &lt;a href="http://blogs.conchango.com/sfts/archive/2008/10/15/configuring-amp-running-the-scrum-for-team-system-report-slide-show-tool.aspx" mce_href="http://blogs.conchango.com/sfts/archive/2008/10/15/configuring-amp-running-the-scrum-for-team-system-report-slide-show-tool.aspx"&gt;Report Slide User Guide Post&lt;/a&gt; from the Scrum for Team System site &lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/new-reporting-features-available-in.html" target="_blank"&gt;New Reporting Features available in Scrum for Team System v2.2&lt;/a&gt;   &lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/build-reports-added-to-scrum-for-team.html" target="_blank"&gt;Build Reports added to Scrum for Team System v2.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The Scrum for Team System report slide show tool&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-version-22.html" target="_blank"&gt;Scrum for Team System Version 2.2 support for SQL Server 2008&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-6318203692441732650?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/6318203692441732650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=6318203692441732650' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6318203692441732650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6318203692441732650'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-report-slide-show.html' title='The Scrum for Team System report slide show tool'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-9186232806516801149</id><published>2008-10-14T21:17:00.002+01:00</published><updated>2010-02-17T21:36:06.729Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='Builds'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v2'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Build Metrics'/><title type='text'>Build Reports added to Scrum for Team System v2.2</title><content type='html'>&lt;a href="http://zogamorph.blogspot.com/2008/10/new-reporting-features-available-in.html"&gt;Continuing from my previous posted&lt;/a&gt;. I’d like to give an overview to the new engineering practices reports included in the Release 2.2.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Builds      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Across a user selected time period (defaulting to the current sprint), this report shows the total builds per day&amp;nbsp;broken down by status.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Static Analysis and Compile      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This displays the number of Errors and Warnings either compile or static analysis the last N number of builds.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZigK9OOI/AAAAAAAAAB4/Fy7RRzcRn3A/s1600-h/Compile8.png" target="_blank"&gt;&lt;img alt="Compile" border="0" height="161" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZjMX7MlI/AAAAAAAAAB8/gHYzIteA0qY/Compile_thumb6.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Compile" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Unit Tests      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Shows the total number of units test run from the last N number of builds. The total is broken down by number status of unit tests for each build. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZkIS_UII/AAAAAAAAACA/lTAeR-FMDWw/s1600-h/UnitTest9.png" target="_blank"&gt;&lt;img alt="UnitTest" border="0" height="183" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZkjmBovI/AAAAAAAAACE/byaxWEXplwg/UnitTest_thumb7.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="UnitTest" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Last Build Unit Test Results&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;This report displays the list of each test that was run for the last build and shows the result of that build. If the unit test failed it will also display the fail message as well. The last build is taken to be the last build within the data warehouse. &lt;br /&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S3xZlRFT4bI/AAAAAAAAACI/55KS0qbmbEI/s1600-h/lastunittest8.png" target="_blank"&gt;&lt;img alt="lastunittest" border="0" height="105" src="http://lh3.ggpht.com/_CJNik6Tu6JU/S3xZmP2G5BI/AAAAAAAAACM/g_ZwEUSs0tU/lastunittest_thumb6.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="lastunittest" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Code Coverage      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This report shows the code coverage of and the total of code churn for last N number of builds. The coverage units can be selected between blocks, which is the visual studio default, lines or partial lines.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZm2qg9kI/AAAAAAAAACQ/wiUSgboGcRY/s1600-h/codecoverage7.png" target="_blank"&gt;&lt;img alt="codecoverage" border="0" height="181" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZnnVx99I/AAAAAAAAACU/Q3sFRdCemcc/codecoverage_thumb5.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="codecoverage" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Code Churn      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This report shows the total “Code Churn Counts” of the last N number of builds broken down by Added, Modified and Deleted lines. This report also features a drill down option which links to the Build Files reports.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xZoeucPqI/AAAAAAAAACY/vtUDGpnxZpc/s1600-h/CodeChurn5.png" target="_blank"&gt;&lt;img alt="CodeChurn" border="0" height="188" src="http://lh5.ggpht.com/_CJNik6Tu6JU/S3xZpeVLueI/AAAAAAAAACc/gySUuhSi9HY/CodeChurn_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="CodeChurn" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Files      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This report, which is also a drill down for the Build Code Churn report, will display the files which were in the build or between two builds. The files are grouped by the folder in which they are located within source control and display the number of Added, Modified and Deleted lines for each of the change sets. Also included is the following change set information: Check-in by, Date, Policy Override Comment. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xZqG19HMI/AAAAAAAAACg/s82ztVTKAwY/s1600-h/BuildFiles5.png" target="_blank"&gt;&lt;img alt="BuildFiles" border="0" height="103" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZqrHpzFI/AAAAAAAAACk/yAV9h4RkdXY/BuildFiles_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="BuildFiles" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Quality      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This report is a based on the MSF for Agile Software Development Quality Indicators. This has been added by popular request and inspired by a blog post by Ed Blankenship: (&lt;a href="http://blogs.infragistics.com/blogs/eblankenship/archive/2007/06/18/msf-agile-quality-indicators-report-for-conchango-scrum-process-template.aspx"&gt;http://blogs.infragistics.com/blogs/eblankenship/archive/2007/06/18/msf-agile-quality-indicators-report-for-conchango-scrum-process-template.aspx&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xZrdQQeRI/AAAAAAAAACo/bvn4zwr-VqM/s1600-h/BuildQuality5.png" target="_blank"&gt;&lt;img alt="BuildQuality" border="0" height="190" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZsJ1LRQI/AAAAAAAAACs/GVk6AAiu0rE/BuildQuality_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="BuildQuality" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build Duration      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This shows how long the last N builds took to complete. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZs0eQJ8I/AAAAAAAAACw/_jEZy_s6JOQ/s1600-h/Duration5.png" target="_blank"&gt;&lt;img alt="Duration" border="0" height="165" src="http://lh5.ggpht.com/_CJNik6Tu6JU/S3xZtcHjNOI/AAAAAAAAAC0/jzXzfMBKfiQ/Duration_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Duration" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Build League      &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This will show a League table of the Top N number of people on their total number builds of Fail or Successful Builds (using either an absolute number or percentage base). This report will run for a selected period defaulting to the currently running sprint. A successful build is defined as any build which not in a state of failed. (Which is not the same as a successful build.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xZtxn-OCI/AAAAAAAAAC4/mUCnS-1sOBM/s1600-h/League5.png" target="_blank"&gt;&lt;img alt="League" border="0" height="94" src="http://lh5.ggpht.com/_CJNik6Tu6JU/S3xZuR8f6JI/AAAAAAAAAC8/iNY4EkHIvF0/League_thumb3.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="League" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;There is one caveat: The way in which a build is counted against a person is if their change set is linked to a build. So some people will gain some builds fails even if their change set is actually not the reason why the build failed. &lt;br /&gt;&lt;br /&gt;All the reports will have the option to select which build type to run against. Also where the reports allow an N number of last builds they have been limited to the following values 10,15,20,25 or 30. &lt;br /&gt;&lt;br /&gt;These reports are not actually link to the Scrum methodology but are helpful tools in the engineering practices. There will be a separate forum for issues and question which can be found here: &lt;a href="http://scrumforteamsystem.com/cs/forums/9/ShowForum.aspx" target="_blank"&gt;Engineering Practices – v2.2 Reports&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/new-reporting-features-available-in.html" target="_blank"&gt;New Reporting Features available in Scrum for Team System v2.2&lt;/a&gt;   &lt;br /&gt;&lt;br /&gt;Build Reports added to Scrum for Team System v2.2&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-report-slide-show.html" target="_blank"&gt;The Scrum for Team System report slide show tool&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-version-22.html" target="_blank"&gt;Scrum for Team System Version 2.2 support for SQL Server 2008&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-9186232806516801149?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/9186232806516801149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=9186232806516801149' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/9186232806516801149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/9186232806516801149'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/10/build-reports-added-to-scrum-for-team.html' title='Build Reports added to Scrum for Team System v2.2'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_CJNik6Tu6JU/S3xZjMX7MlI/AAAAAAAAAB8/gHYzIteA0qY/s72-c/Compile_thumb6.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-7803422586759402993</id><published>2008-10-14T20:31:00.001+01:00</published><updated>2010-02-17T21:29:50.070Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Reporting'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v2'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><title type='text'>New Reporting Features available in Scrum for Team System v2.2</title><content type='html'>To coincide with the release of version 2.2 of Scrum for Team System, I’d like to bring your attention to the wide range of new reports included in this release. I’ve been heavily involved in the Scrum for Team System process template since the start of version 2 and have written the majority of the new reports and tweaked some of the old ones to improve performance by moving some of the querying to the TFS cube, as well as reflecting user feedback.&lt;br /&gt;&lt;br /&gt;One such fix, which can be found in release, was to the burn down report which would show a misleading (but accurate) trend line if the task data wasn’t updated on the very first day of the sprint. (This could also be fixed by making your Scrum Master work harder, but I don’t have any control over that so I decided to tweak the report instead). &lt;br /&gt;&lt;br /&gt;Most of the new reports in this release are focussed on engineering practices, which I will cover another blog post; however there is one new report specifically targeted for Scrum called the velocity report.&lt;br /&gt;Velocity is based upon the recorded historical performance of a team, and is a fantastic tool for accurate release planning; for more details please see my colleague &lt;a class="class" href="http://blogs.conchango.com/simonbennett/archive/2008/12/17/release-planning-using-the-scrum-for-team-system-velocity-report.aspx" mce_href="/simonbennett/archive/2008/12/17/release-planning-using-the-scrum-for-team-system-velocity-report.aspx"&gt;Simon Bennett’s&lt;/a&gt; blog for more details.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S3xbVL20YnI/AAAAAAAAADA/O6VHNCqWBzg/s1600-h/Velocity14.png" target="_blank"&gt;&lt;img alt="Velocity" border="0" height="147" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S3xbVtk7hgI/AAAAAAAAADE/oHav5T7Bjpg/Velocity_thumb10.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Velocity" width="240" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;So onto the new reports.... &lt;br /&gt;&lt;br /&gt;New Reporting Features available in Scrum for Team System v2.2&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/build-reports-added-to-scrum-for-team.html" target="_blank"&gt;Build Reports added to Scrum for Team System v2.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-report-slide-show.html" target="_blank"&gt;The Scrum for Team System report slide show tool&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zogamorph.blogspot.com/2008/10/scrum-for-team-system-version-22.html" target="_blank"&gt;Scrum for Team System Version 2.2 support for SQL Server 2008&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-7803422586759402993?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/7803422586759402993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=7803422586759402993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/7803422586759402993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/7803422586759402993'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/10/new-reporting-features-available-in.html' title='New Reporting Features available in Scrum for Team System v2.2'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_CJNik6Tu6JU/S3xbVtk7hgI/AAAAAAAAADE/oHav5T7Bjpg/s72-c/Velocity_thumb10.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-5181130278401153238</id><published>2008-09-30T22:30:00.008+01:00</published><updated>2010-02-15T22:02:00.744Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='NDepend'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Build Metrics'/><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='ReSharper'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS Custom Adapters'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD .Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Unit Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><title type='text'>Using NDepend to help guide Refactoring</title><content type='html'>In my &lt;a href="http://zogamorph.blogspot.com/2008/07/building-team-foundation-server-custom.html" target="_blank"&gt;other&lt;/a&gt; blogs &lt;a href="http://zogamorph.blogspot.com/2008/07/how-i-built-team-foundation-server.html" target="_blank"&gt;entries&lt;/a&gt; I mention that I have been looking into building a Team Foundation Server Data Warehouse Adapter.&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;After I got my initial proof of concept version working, I started to extend it to get a list of available builds from TFS and then import the output of &lt;a href="http://www.campwoodsw.com/sourcemonitor.html" mce_href="http://www.campwoodsw.com/sourcemonitor.html"&gt;Source Monitor&lt;/a&gt; – a popular free code metrics tool. &lt;br /&gt;&lt;br /&gt;Now I must state that I am not a natural .NET coder. My normal day-to-day work is based around the SQL Server technology stack. I do have some .NET coding skills but generally just enough for what is need in and around SQL Server. So I asked my colleague, &lt;a href="http://howard.vanrooijen.co.uk/blog/"&gt;Howard van Rooijen&lt;/a&gt; who is one of our top .NET coders, to have a look at my code and give me some hints. &lt;br /&gt;&lt;br /&gt;This provide me with a great opportunity to learn from Howard about some more advance Design Patterns,&amp;nbsp; &lt;a href="http://blogs.msdn.com/saraford/default.aspx" mce_href="http://blogs.msdn.com/saraford/default.aspx"&gt;Visual Studio tips and tricks&lt;/a&gt;, and how to effectively use some tools I’ve not used before to help me write better code. The first thing Howard did was install the following on my machine: &lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.jetbrains.com/resharper/" mce_href="http://www.jetbrains.com/resharper/"&gt;ReSharper&lt;/a&gt; – to help me refactor the code, fortunately we have just rolled out ReSharper licenses to all .NET Developers!&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.msdn.microsoft.com/sourceanalysis" mce_href="http://code.msdn.microsoft.com/sourceanalysis"&gt;StyleCop&lt;/a&gt; – to help remind me of the Microsoft C# Coding Conventions&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.testdriven.net/" mce_href="http://www.testdriven.net/"&gt;TDD.NET&lt;/a&gt; –&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;to ease the pain of running my unit tests&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ndepend.com/" mce_href="http://www.ndepend.com/"&gt;NDepend&lt;/a&gt; – a code metrics tool&lt;/li&gt;&lt;/ul&gt;&lt;div class="MsoNormal"&gt;Howard wanted to integrate NDepend into my TFS Data Warehouse Adapter and suggested that the best way to understand the tool would be to use it to analyse my TFS Adapter code and see if it would be able to give the direction on where to focus our refactoring efforts.&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;NDepend &lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp;&lt;/span&gt;comes with &lt;a href="http://www.ndepend.com/Features.aspx#Metrics" mce_href="http://www.ndepend.com/Features.aspx#Metrics"&gt;82 code metrics&lt;/a&gt; out of the box, but it’s far more than a standard code metrics tool. It comes with a bundle of best practice design rules which are written using &lt;a href="http://www.ndepend.com/Features.aspx#CQL" mce_href="http://www.ndepend.com/Features.aspx#CQL"&gt;Code Query Language&lt;/a&gt; – an idea so &lt;a href="http://www.ndepend.com/CQL.htm" mce_href="http://www.ndepend.com/CQL.htm"&gt;simple and elegant&lt;/a&gt; that I bet the FxCop team are kicking themselves for not thinking of it first. CQL allows you to write statements like:&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: green; font-size: 10pt; line-height: 115%;" white;="white;"&gt;// &lt;name&gt;Methods poorly commented&lt;/name&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: green; font-size: 10pt; line-height: 115%;" white;="white;"&gt;&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;WARN&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;IF&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: #000064; font-size: 10pt; line-height: 115%;" white;="white;"&gt;Count&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &amp;gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: yellow; color: black; font-size: 10pt; line-height: 115%;" yellow;="yellow;"&gt;0&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;IN&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;SELECT&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;METHODS&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;WHERE&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: #000064; font-size: 10pt; line-height: 115%;" white;="white;"&gt;PercentageComment&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &amp;lt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: yellow; color: black; font-size: 10pt; line-height: 115%;" yellow;="yellow;"&gt;20&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;AND&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: #000064; font-size: 10pt; line-height: 115%;" white;="white;"&gt;NbLinesOfCode&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &amp;gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: yellow; color: black; font-size: 10pt; line-height: 115%;" yellow;="yellow;"&gt;15&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt;&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;ORDER&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;BY&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: #000064; font-size: 10pt; line-height: 115%;" white;="white;"&gt;PercentageComment&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: black; font-size: 10pt; line-height: 115%;" white;="white;"&gt; &lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" mso-highlight:="mso-highlight:" new?;="new?;" style="background: white; color: blue; font-size: 10pt; line-height: 115%;" white;="white;"&gt;ASC&lt;/span&gt;&lt;span courier="courier" fr?="FR?" lang="FR" mso-ansi-language:="mso-ansi-language:" new?;="new?;" style="color: blue; font-size: 10pt; line-height: 115%;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;You can even embed CQL directly into your code via attributes. NDepend also has features like being able to compare different builds (&lt;a href="http://codebetter.com/blogs/patricksmacchia" mce_href="http://codebetter.com/blogs/patricksmacchia"&gt;Patrick Smacchia&lt;/a&gt;, NDepend’s developer &lt;a href="http://codebetter.com/blogs/patricksmacchia/archive/2008/08/13/net-3-5-sp1-changes-overview.aspx" mce_href="http://codebetter.com/blogs/patricksmacchia/archive/2008/08/13/net-3-5-sp1-changes-overview.aspx"&gt;demonstrated this feature&lt;/a&gt; on the recent .NET Framework 3.5 SP1 release), manage complexity, dependencies and monitor the health of your build process.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;We started by running my code through NDepend and the initial results were that my code has high instability and not at all abstracted.&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;I couldn’t really affect the instability as my code was just a thin wrapper around the TFS API.&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;It also highlight that some of my old best practices that needed updating as many of them are now redundant with C# 2.0 features (generics, static classes etc). It also highlighted performance gains I could make.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;Howard said that he was having some difficulties understanding what the intention of my code was, as he was unfamiliar with building Data Warehouse Adapters. He asked me if I could write some unit tests that would call the code and verify the output – so he could use the “Test with... Debugger” feature of TDD.NET to see what was going on with the code. &lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;Once I had written some tests, Howard wrote two more: one that passed in a null value and another that passed in an empty string; these, he explained were two valid edge cases for handling bad data and to my surprise both tests failed! Once I fixed both failing tests, he asked me to run the whole test suite again and this time I was really surprised as all of my previously passing tests now failed! The issue was with two helper methods that convert string based representations of number within the Data Warehouse into valid number primitives.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;NDepend pointed out lots of issues with these methods and Howard said that a simple Regular Expression could replace a lot of the parsing logic I had written, so I set about refactoring the code.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Before:&lt;/b&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CleanInt(&lt;span class="kwrd"&gt;string&lt;/span&gt; number) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; foundNonDigit = &lt;span class="kwrd"&gt;false&lt;/span&gt;; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; index = 0; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (number == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;"0"&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (!foundNonDigit) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;char&lt;/span&gt;.IsDigit(number[index])) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            result = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"{0}{1}"&lt;/span&gt;, result, number[index]); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;            index++; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;            foundNonDigit = result.Length &amp;gt; 0; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;        } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; result; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CleanFloat(&lt;span class="kwrd"&gt;string&lt;/span&gt; number) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; foundNonDigit = &lt;span class="kwrd"&gt;false&lt;/span&gt;; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; foundDecmialPoint = &lt;span class="kwrd"&gt;false&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; index = 0; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (number == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;"0"&lt;/span&gt;; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (!foundNonDigit) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;char&lt;/span&gt;.IsDigit(number[index]) || (number[index] == &lt;span class="str"&gt;'.'&lt;/span&gt; &amp;amp;&amp;amp; !foundDecmialPoint)) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;            result = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"{0}{1}"&lt;/span&gt;, result, number[index]); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;            foundDecmialPoint = number[index] == &lt;span class="str"&gt;'.'&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;            index++; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;        } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;            foundNonDigit = result.Length &amp;gt; 0; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;        } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; result; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto; mso-margin-top-alt: auto;"&gt;&lt;span courier="courier" en-gb;="EN-GB;" mso-fareast-language:="mso-fareast-language:" mso-no-proof:="mso-no-proof:" new?;="new?;" style="font-size: 9pt;" yes?="yes?"&gt;&lt;/span&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;span style="font-size: 9pt;"&gt;After:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CleanInt(&lt;span class="kwrd"&gt;string&lt;/span&gt; number) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; resultFromTryParse; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="rem"&gt;// check for empty string after cleaning string &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (number.Trim() == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;"0"&lt;/span&gt;; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="rem"&gt;// if try parse works return the number in string format &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;.TryParse(number, &lt;span class="kwrd"&gt;out&lt;/span&gt; resultFromTryParse)) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; resultFromTryParse.ToString(); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    &lt;span class="rem"&gt;// else return results of clean GetCleanNumberString &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; GetCleanNumberString(number, &lt;span class="str"&gt;"Integers"&lt;/span&gt;); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CleanFloat(&lt;span class="kwrd"&gt;string&lt;/span&gt; number) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    &lt;span class="kwrd"&gt;float&lt;/span&gt; resultFromTryParse; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="rem"&gt;// clean the number and check to see if it's empty &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    number = number.Trim(); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (number == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;"0"&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;    &lt;span class="rem"&gt;// try parse the number if works the return the number &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;float&lt;/span&gt;.TryParse(number, &lt;span class="kwrd"&gt;out&lt;/span&gt; resultFromTryParse)) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; number; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    &lt;span class="rem"&gt;// returns result of Get clean number &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; GetCleanNumberString(number, &lt;span class="str"&gt;"Floats"&lt;/span&gt;); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetCleanNumberString(&lt;span class="kwrd"&gt;string&lt;/span&gt; number, &lt;span class="kwrd"&gt;string&lt;/span&gt; numberType) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    &lt;span class="rem"&gt;// Create a regualr patten with name groups do a macth on the number entered &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;    Regex regex = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"(?&amp;lt;Floats&amp;gt;(?&amp;lt;Integers&amp;gt;\d+)+\.\d+)|(?&amp;lt;Integers&amp;gt;\d+)"&lt;/span&gt;, RegexOptions.Singleline); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;    Match match = regex.Match(number); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; results = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;    &lt;span class="rem"&gt;// if match groups are found the return the string &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (match.Groups != &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;        results = match.Groups[numberType].Value; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; results; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;&lt;span courier="courier" en-gb;="EN-GB;" mso-fareast-language:="mso-fareast-language:" mso-no-proof:="mso-no-proof:" new?;="new?;" style="font-size: 9pt;" yes?="yes?"&gt;&lt;/span&gt;Now all my tests passed and NDepend was happy too.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;Next NDepend highlighted some of my methods that had too many lines of code. Howard said he was having a bit of difficulty understanding what the code was doing and explained to me the notion of &lt;a href="http://www.informit.com/articles/article.aspx?p=357688" mce_href="http://www.informit.com/articles/article.aspx?p=357688"&gt;Programming by Intention&lt;/a&gt;. &lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;Next he paired with me and went through the method reformatting the code. He said that by reformatting, reorganising and removing redundant variables you start to see patterns forming within the code, that clumps of logic naturally come together and how you can then use ReSharper’s &lt;i style="mso-bidi-font-style: normal;"&gt;Extract Method&lt;/i&gt; refactoring to extract that clump of code into a separate method. Now instead of having a mass of hard to understand code – the method simply listed a series of steps that occurred – the intention of the method had been made clear. Howard was happy because he now understood what the method was doing and NDepend was happy as the method was now shorter and a great deal less complex.&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;In my original proof of concept I had used partial classes as a mechanism to extend the main TFS Data Warehouse Adapter and implemented another partial class in order to integrate Source Monitor.&lt;span style="mso-spacerun: yes;"&gt;&amp;nbsp; &lt;/span&gt;Howard pointed out that this approach wouldn’t work if we wanted to integrate a second tool. &lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;He said that now we had cleaned up the code and broken down the few large methods into a series of smaller methods we had surfaced the behaviour required to integrate an external code metrics tool into the Data Warehouse Adapter and that we could use ReSharper’s &lt;i style="mso-bidi-font-style: normal;"&gt;Extract Interface&lt;/i&gt; refactoring to move the definitions of this behaviour into an interface called &lt;span courier="courier" new??="new??"&gt;ICodeMetricAdapter&lt;/span&gt; and then use this interface to implement any other 3&lt;sup&gt;rd&lt;/sup&gt; party code metrics tool. &lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;Howard said that we had now essentially implemented the &lt;a href="http://www.dofactory.com/Patterns/PatternAdapter.aspx" mce_href="http://www.dofactory.com/Patterns/PatternAdapter.aspx"&gt;adapter pattern&lt;/a&gt;. Next we refactored the existing code to use the interface instead of the concrete type and we extracted the Source Monitor code into a new file called &lt;span courier="courier" new??="new??"&gt;SourceMonitorAdapter&lt;/span&gt; which implemented the &lt;span courier="courier" new??="new??"&gt;ICodeMetricAdapter&lt;/span&gt; interface. We added a &lt;span courier="courier" new??="new??"&gt;List&amp;lt;ICodeMetricAdapter&lt;/span&gt;&amp;gt; to the parent object and then refactored the code to loop through this list and then call the current &lt;span courier="courier" new??="new??"&gt;ICodeMetricAdapter&lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;.&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;We managed to get this all done in one afternoon, just as I was packing up Howard asked me “Now, what do you need to do to add an NDepend Adapter?” I created a new class called &lt;span courier="courier" new??="new??"&gt;NDependAdapter&lt;/span&gt; and made it implement &lt;span courier="courier" new??="new??"&gt;ICodeMetricAdapter&lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;. &lt;/i&gt;Howard showed me that I could use the &lt;i style="mso-bidi-font-style: normal;"&gt;Implement Members&lt;/i&gt; quick fix by selecting the interface and hitting ALT-ENTER. Then all I had to do was add a new instance of the &lt;span courier="courier" new??="new??"&gt;NDependAdapter&lt;/span&gt; to the &lt;span courier="courier" new??="new??"&gt;List&amp;lt;ICodeMetricAdapter&amp;gt;&lt;/span&gt; and the new &lt;span courier="courier" new??="new??"&gt;NDependAdapter&lt;/span&gt; is automatically called!&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;Below is the before and after class diagrams of the solution:&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Before: &lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;&lt;a href="http://lh6.ggpht.com/_CJNik6Tu6JU/S3m9aZv_nzI/AAAAAAAAABo/sZdFqO2BLnk/s1600-h/TFSWarehouseAdpterBefore%5B6%5D.png" target="_blank"&gt;&lt;img alt="TFSWarehouseAdpterBefore" border="0" height="480" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3m9bISizgI/AAAAAAAAABs/LkaQhUTAIDg/TFSWarehouseAdpterBefore_thumb%5B4%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="TFSWarehouseAdpterBefore" width="336" /&gt;&lt;/a&gt; &lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;span style="font-size: 9pt;"&gt;After:&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 9pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormalCxSpMiddle" style="line-height: normal; mso-add-space: auto; mso-margin-bottom-alt: auto;"&gt;&lt;a href="http://lh3.ggpht.com/_CJNik6Tu6JU/S3m9cLGF_4I/AAAAAAAAABw/c6miaG2_Wh0/s1600-h/TFSWarehouseAdpterAfter%5B6%5D.png" target="_blank"&gt;&lt;img alt="TFSWarehouseAdpterAfter" border="0" height="480" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3m9dOYmqPI/AAAAAAAAAB0/5f3vfg65XbA/TFSWarehouseAdpterAfter_thumb%5B4%5D.png?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="TFSWarehouseAdpterAfter" width="387" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-5181130278401153238?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/5181130278401153238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=5181130278401153238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5181130278401153238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5181130278401153238'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/09/using-ndepend-to-help-guide-refactoring.html' title='Using NDepend to help guide Refactoring'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_CJNik6Tu6JU/S3m9bISizgI/AAAAAAAAABs/LkaQhUTAIDg/s72-c/TFSWarehouseAdpterBefore_thumb%5B4%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4551345798003955601</id><published>2008-07-11T21:53:00.001+01:00</published><updated>2010-02-15T21:04:17.153Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS Custom Adapters'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Builds'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Build Metrics'/><title type='text'>How I built a Team Foundation Server custom data warehouse adapter</title><content type='html'>As mentioned in a &lt;a href="http://zogamorph.blogspot.com/2008/07/building-team-foundation-server-custom.html" target="_blank"&gt;previous blog&lt;/a&gt; I would like to explain some of the steps I took to get my custom data warehouse adapter to work.&amp;nbsp; I am going to start from the beginning just so that I have an easy starting point.&amp;nbsp; The code I show here was based upon my POC and written in C#.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;1. Create a new C# Class Library project in Visual Studio. Then add references at least to the following assemblies: Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll, Microsoft.TeamFoundation.Common.dll, Microsoft.TeamFoundation.Warehouse.dll and System.Web. As I need to connect to the build server I added Microsoft.TeamFoundation.Build.Common.dll and Microsoft.TeamFoundation.Build.Client.dll &lt;/li&gt;&lt;li&gt;2. Then specify the use of the IWarehouseAdapter interface. &lt;/li&gt;&lt;li&gt;3. Implement IWarehouseAdapter.RequestStop which only sets a stop flag to true which can then be tested by the other methods periodically. &lt;/li&gt;&lt;li&gt;4. Implement the IWarehouseAdapter.Initialize. This method this where I need to store objects that will need to communicate to the all systems that you adapter needs to talk to i.e.: &lt;/li&gt;&lt;/ol&gt;&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1: &lt;/span&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; url;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;TeamFoundationServer tfs;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;_DataStore = ds;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (_DataStore == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;   &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"Null data store."&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;url = Microsoft.TeamFoundation.Server.TeamFoundationApplication.TfsNameUrl;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;tfs = TeamFoundationServerFactory.GetServer(url);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (tfs == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;   &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"TF Server instance not obtained for TFS url: "&lt;/span&gt; + url);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;_BuildServer = (IBuildServer)tfs.GetService(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IBuildServer)); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (_BuildServer == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;   &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"Build Server instance not obtained for TFS url: "&lt;/span&gt; + url);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;_CommonStructureService = (ICommonStructureService)tfs.GetService(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ICommonStructureService));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (_CommonStructureService == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;   &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"Common Structure Service instance not obtained for TFS url: "&lt;/span&gt; + url);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;} &lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;5. Implement the IWarehouseAdapter.MakeSchemaChanges. This method is called to see if there are schema changes that would need to be made to the data warehouse.&amp;nbsp; This is recommended to be where you actually register your changes you need to make to the warehouse i.e.:&amp;nbsp; &lt;/li&gt;&lt;/ol&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;SchemaChangesResult result = SchemaChangesResult.NoChanges; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;//Get the current data warehouse configuration  &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;WarehouseConfig warehouseConfig = _DataStore.GetWarehouseConfig(); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;//As the IWarehouseAdapter.MakeSchemaChanges can be called many times in one sessions &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="rem"&gt;//I needed to see if your fact was already created &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;Fact MyNewFact = warehouseConfig.GetFact(&lt;span class="str"&gt;"MyNewFact"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (MyNewFact == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="rem"&gt;//Create My New Fact&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    MyNewFact = &lt;span class="kwrd"&gt;new&lt;/span&gt; Fact(); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    MyNewFact.Name = &lt;span class="str"&gt;"MyNewFact"&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;      &lt;span class="rem"&gt;//Adding a link to the Team Project – I had to do this otherwise my save would not work&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    MyNewFact.DimensionUses.Add(CreateDimensionUse(&lt;span class="str"&gt;"Team Project"&lt;/span&gt;, &lt;span class="str"&gt;"Team Project"&lt;/span&gt;));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="rem"&gt;//Adding a link to the Build dimension also when use the dimension I needed to &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;      &lt;span class="rem"&gt;//find out the dimension key attribute was for when saving my data. &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    MyNewFact.DimensionUses.Add(CreateDimensionUse(&lt;span class="str"&gt;"Build"&lt;/span&gt;, &lt;span class="str"&gt;"Build"&lt;/span&gt;));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    MyNewFact.Fields.Add(CreateField(&lt;span class="str"&gt;"measure1"&lt;/span&gt;,&lt;span class="str"&gt;"int"&lt;/span&gt;,0,&lt;span class="str"&gt;"Sum"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    MyNewFact.Fields.Add(CreateField(&lt;span class="str"&gt;"measure2"&lt;/span&gt;, &lt;span class="str"&gt;"int"&lt;/span&gt;,  0, &lt;span class="str"&gt;"Sum"&lt;/span&gt;));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    &lt;span class="rem"&gt;//Setting which perspective it would show under if enterprise edition of AS was in use.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    MyNewFact.PerspectiveName = &lt;span class="str"&gt;"Code Churn"&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    MyNewFact.IncludeCountMeasure = &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!_StopRequest)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;      {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;           &lt;span class="rem"&gt;//Starting a Transaction to rollback my changes if they fail &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;           _DataStore.BeginTransaction();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;          &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;          {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;                 &lt;span class="rem"&gt;//Adding to the data warehouse configuration xml file and saving the changes &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;                 warehouseConfig.Facts.Add(MyNewFact);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;                 _DataStore.Add(warehouseConfig);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;                 _DataStore.CommitTransaction();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;                 result = SchemaChangesResult.ChangesComplete;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;           }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;           &lt;span class="kwrd"&gt;catch&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;           {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;                 _DataStore.RollbackTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;           }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;        result = SchemaChangesResult.StopRequested; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; result; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;&lt;span class="rem"&gt;//The functions to create a new field and dimension link&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; Field CreateField(&lt;span class="kwrd"&gt;string&lt;/span&gt; FieldName, &lt;span class="kwrd"&gt;string&lt;/span&gt; FieldType, &lt;span class="kwrd"&gt;short&lt;/span&gt; FieldLength, &lt;span class="kwrd"&gt;string&lt;/span&gt; FieldAggregationFunction) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;    Field newField = &lt;span class="kwrd"&gt;new&lt;/span&gt; Field();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;    newField.Name = FieldName;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;    newField.Type = FieldType;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;    newField.Length = FieldLength;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;    newField.AggregationFunction = FieldAggregationFunction;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; newField;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; DimensionUse CreateDimensionUse(&lt;span class="kwrd"&gt;string&lt;/span&gt; DimensionName, &lt;span class="kwrd"&gt;string&lt;/span&gt; UseName) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;    DimensionUse dimensionUse = &lt;span class="kwrd"&gt;new&lt;/span&gt; DimensionUse();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;    dimensionUse.DimensionName = DimensionName;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;    dimensionUse.UseName = UseName;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; dimensionUse;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;6. IWarehouseAdapter.MakeDataChanges which is where all the transferring and transforming of the data takes place. &lt;/li&gt;&lt;/ol&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;IEnumerator projectEnum = _CommonStructureService.ListAllProjects().GetEnumerator();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;DataChangesResult result = DataChangesResult.NoChanges;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;IEnumerator buildEnum;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;IBuildDetail[] buildDetails;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;ProjectInfo currentTeamProject;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;DateTime buildStartSearch = LastMyNewFactPrcoessedDateTime;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;DateTime buildEndSearch = DateTime.Now; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;while&lt;/span&gt; (projectEnum.MoveNext())&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="rem"&gt;//checking to see if a stop request has happend if so then return the fact that a stop happen.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_StopRequest&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; DataChangesResult.StopRequested;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="rem"&gt;//Just checking the state of the project as I am not interested in deleted projects&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    currentTeamProject = projectEnum.Current &lt;span class="kwrd"&gt;as&lt;/span&gt; ProjectInfo;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (currentTeamProject.Status != ProjectState.Deleting)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="rem"&gt;//Get a list of builds and the filter the out builds that I have already processed.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        buildDetails = _BuildServer.QueryBuilds(currentTeamProject.Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;        var filterBuildList = from bd &lt;span class="kwrd"&gt;in&lt;/span&gt; buildDetails&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;        &lt;span class="kwrd"&gt;where&lt;/span&gt; bd.StartTime &amp;gt;= buildStartSearch&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;        &amp;amp;&amp;amp; bd.FinishTime &amp;lt; buildEndSearch&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;        select bd;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        &lt;span class="rem"&gt;//From my new list of builds save my fact details&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;        buildEnum = filterBuildList.GetEnumerator();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;        &lt;span class="kwrd"&gt;while&lt;/span&gt; (buildEnum.MoveNext())&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_StopRequest)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; DataChangesResult.StopRequested;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;            SaveMyNewFactEntry (buildEnum.Current &lt;span class="kwrd"&gt;as&lt;/span&gt; IBuildDetail, currentTeamProject); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;        &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;            &lt;span class="rem"&gt;//Update the last build started and date I have just covered.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;            LastMyNewFactPrcoessedDateTime = buildEndSearch;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;            result = DataChangesResult.ChangesComplete;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveMyNewFactEntry (IBuildDetail buildDetail, ProjectInfo currentProject)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;    Random rand = &lt;span class="kwrd"&gt;new&lt;/span&gt; Random();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;    &lt;span class="rem"&gt;//Check to see if this build has been already added to fact table.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; buildURI = LinkingUtilities.DecodeUri(buildDetail.Uri.AbsoluteUri).ToolSpecificId;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_DataStore.GetFactEntry(&lt;span class="str"&gt;"Build Details"&lt;/span&gt;, buildURI) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;        FactEntry newFactEntry = _DataStore.CreateFactEntry(&lt;span class="str"&gt;"MyNewFact "&lt;/span&gt;); &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;        &lt;span class="rem"&gt;// Had to add Tracking ID by not doing so cause an error.  The Tracking ID is used to find facts &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;        &lt;span class="rem"&gt;//So need make sure that method which repeatable for the same fact entry each time. &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;        newFactEntry.TrackingId = Guid.NewGuid().ToString(&lt;span class="str"&gt;"D"&lt;/span&gt;, CultureInfo.InvariantCulture);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;        newFactEntry [&lt;span class="str"&gt;"Team Project"&lt;/span&gt;] = LinkingUtilities.DecodeUri(currentProject.Uri).ToolSpecificId;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;        newFactEntry [&lt;span class="str"&gt;"Build"&lt;/span&gt;] = buildURI; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;        newFactEntry [&lt;span class="str"&gt;"measure1"&lt;/span&gt;] = rand.Next(0,100);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;        newFactEntry [&lt;span class="str"&gt;"measure2"&lt;/span&gt;] = rand.Next(0, 100);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;        &lt;span class="rem"&gt;//Again create a transaction save the entry if successful commit the changes&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;        _DataStore.BeginTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  75:  &lt;/span&gt;            _DataStore.SaveFactEntry(newFact, &lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  76:  &lt;/span&gt;            _DataStore.CommitTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  78:  &lt;/span&gt;        &lt;span class="kwrd"&gt;catch&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  79:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  80:  &lt;/span&gt;            _DataStore.RollbackTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  81:  &lt;/span&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  82:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  83:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  84:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  85:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  86:  &lt;/span&gt;} &lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;7. I need to store the last date processed so I created a property which stores the data in the datastore property bag. &lt;/li&gt;&lt;/ul&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;// Last changeset that was populated.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime LastMyNewFactPrcoessedDateTime&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    get&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        String LastMyNewFactPrcoessedDateTimeStr = _DataStore.GetProperty(&lt;span class="str"&gt;"Last MyNewFact Prcoessed DateTime"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        DateTime lastMyNewFactPrcoessedDateTime = DateTime.MinValue;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(LastMyNewFactPrcoessedDateTimeStr))&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;            lastMyNewFactPrcoessedDateTime = DateTime.Parse(LastMyNewFactPrcoessedDateTimeStr);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; lastMyNewFactPrcoessedDateTime;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    set&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    { &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        _DataStore.BeginTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        { &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;            _DataStore.SetProperty(&lt;span class="str"&gt;"Last MyNewFact Prcoessed DateTime"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;.ToString());&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;            _DataStore.CommitTransaction();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="kwrd"&gt;catch&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;            _DataStore.RollbackTransaction();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;8. Build the adapter as a DLL. &lt;/li&gt;&lt;li&gt;9. Copy the build DLL into the warehouse plugins folder on the application tier.&amp;nbsp; In most cases will be C:\Program Files\Microsoft Visual Studio 2008 Team Foundation Server\Web Services\Warehouse\bin\Plugins. &lt;/li&gt;&lt;li&gt;10. Reset IIS. &lt;/li&gt;&lt;li&gt;11. On the application tier, navigate to &lt;a href="http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run" mce_href="http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run"&gt;http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run&lt;/a&gt; and click Invoke. &lt;/li&gt;&lt;li&gt;12. On the application tier, navigate to &lt;a href="http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=GetWarehouseStatus" mce_href="http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=GetWarehouseStatus"&gt;http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=GetWarehouseStatus&lt;/a&gt; and click Invoke. Continue doing this until the status is returned as Idle. Check the application event log, to see if an exception has been thrown. &lt;/li&gt;&lt;li&gt;13. Reset IIS. &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;If you wish to find out what your current warehouse configuration is then run the following query against your TFS warehouse: &lt;br /&gt;&lt;br /&gt;SELECT CAST(wc.Setting AS XML) AS setting FROM dbo.[_WarehouseConfig] AS wc WHERE wc.ID = 'ConfigXML'&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4551345798003955601?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4551345798003955601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4551345798003955601' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4551345798003955601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4551345798003955601'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/07/how-i-built-team-foundation-server.html' title='How I built a Team Foundation Server custom data warehouse adapter'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-806757888582778670</id><published>2008-07-11T21:48:00.000+01:00</published><updated>2010-02-15T20:49:05.586Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS Custom Adapters'/><category scheme='http://www.blogger.com/atom/ns#' term='Builds'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Build Metrics'/><title type='text'>Building a Team Foundation Server custom data warehouse adapter</title><content type='html'>&lt;p&gt;I have been investigating a way of adding more metrics about our builds into the Team Foundation Server 2008 warehouse.&amp;#160; This would then allow us to measure quality of our code over time by other metrics than the just method offered by the Team Foundation Server 2008.&lt;/p&gt;  &lt;p&gt;So my goal was to create a new fact table and link this to build dimension.&amp;#160; The reason for building a fact table was the metrics as I would want to do some aggregation against them; this would mean I need to treat them as measures and measures only live in a fact table.&amp;#160; I also wanted a separate fact table so my adapter doesn’t impact the standard TFS adapters.&amp;#160; &lt;br /&gt;As my facts would be generated by builds it would mean that facts would link to the build which why I used the build dimension.&amp;#160; Also I found out later I had to also include the Team Project dimension as well.&lt;/p&gt;  &lt;p&gt;I managed to find some useful links that helped me write my adapter:&lt;/p&gt;  &lt;blockquote&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb130342.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb130342.aspx"&gt;http://msdn.microsoft.com/en-us/library/bb130342.aspx&lt;/a&gt; - This section covers several topics: how to implement an adapter; how the data warehouse is created and gives example on how to create adapter.&amp;#160; The example is only how to extend existing dimensions not how to create new objects.     &lt;p&gt;&lt;a href="http://tomfury.spaces.live.com/blog/" mce_href="http://tomfury.spaces.live.com/blog/"&gt;http://tomfury.spaces.live.com/blog/&lt;/a&gt; - This guy was trying to do the same thing as me and created a series of blog entries explaining what he was doing and his issues he was facing and gave some code examples.&amp;#160; Also he has posted the following questions on the forums which were helpful:&lt;/p&gt;    &lt;blockquote&gt;     &lt;p&gt;&lt;a href="http://forums.microsoft.com/MSDN/showpost.aspx?postid=2464644&amp;amp;siteid=1" mce_href="http://forums.microsoft.com/MSDN/showpost.aspx?postid=2464644&amp;amp;siteid=1"&gt;http://forums.microsoft.com/MSDN/showpost.aspx?postid=2464644&amp;amp;siteid=1&lt;/a&gt;         &lt;br /&gt;&lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1644099&amp;amp;SiteID=1" mce_href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1644099&amp;amp;SiteID=1"&gt;http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1644099&amp;amp;SiteID=1&lt;/a&gt;         &lt;br /&gt;&lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2518423&amp;amp;SiteID=1" mce_href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2518423&amp;amp;SiteID=1"&gt;http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2518423&amp;amp;SiteID=1&lt;/a&gt;&lt;/p&gt;   &lt;/blockquote&gt; &lt;/blockquote&gt;  &lt;p&gt;There some has been some changes, as I understand, between 2005 and 2008. As I no longer code against TFS 2005 I can’t make any real comment about these.&amp;#160; However I found these links helpful for coding against TFS 2008:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://ozgrant.com/2006/06/18/how-to-list-tfs-team-projects-using-the-api/" mce_href="http://ozgrant.com/2006/06/18/how-to-list-tfs-team-projects-using-the-api/"&gt;http://ozgrant.com/2006/06/18/how-to-list-tfs-team-projects-using-the-api/&lt;/a&gt; - this to gain information about the projects that are in TFS server.&lt;/p&gt;    &lt;p&gt;&lt;a href="http://notsosmartbuilder.blogspot.com/2007/09/team-build-2008-api.html" mce_href="http://notsosmartbuilder.blogspot.com/2007/09/team-build-2008-api.html"&gt;http://notsosmartbuilder.blogspot.com/2007/09/team-build-2008-api.html&lt;/a&gt; - this helped me to query TFS server about the builds it understands.&amp;#160; As I can see there has been a lot of changes between the 2005 and 2008.&amp;#160; In the 2008 API some namespaces have been made obsolete (Microsoft.TeamFoundation.Build.Proxy; also a few classes in Microsoft.TeamFoundation.Build.Common).&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;To see how I wrote my custom TFS data warehouse adapter please &lt;a class="class" href="http://blogs.conchango.com/stevewright/archive/2008/07/11/how-i-built-a-team-foundation-server-custom-data-warehouse-adapter.aspx" target="_blank" mce_href="/stevewright/archive/2008/07/11/how-i-built-a-team-foundation-server-custom-data-warehouse-adapter.aspx"&gt;click here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-806757888582778670?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/806757888582778670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=806757888582778670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/806757888582778670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/806757888582778670'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/07/building-team-foundation-server-custom.html' title='Building a Team Foundation Server custom data warehouse adapter'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-5322250190356323162</id><published>2008-06-10T19:22:00.000+01:00</published><updated>2010-02-15T18:23:42.952Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP EndPoints'/><title type='text'>Could HTTP Soap / T-SQL endpoint be replaced by Reporting Services XML Reports?</title><content type='html'>&lt;p&gt;I have been working on a POC using SQL Server 2008 and Google Maps.&amp;#160; The POC was to use Geo Spatial technology to illustrate our Geo Spatial data easily.&amp;#160;&amp;#160; I will talk about this in more detail in another blog post as I would like talk about a problem I faced while creating this POC.&amp;#160; &lt;/p&gt;  &lt;p&gt;The problem I faced was how could I get my Geo Spatial data, which was stored within SQL Server 2008 using the new geography data type, into&amp;#160; &amp;quot;static&amp;quot; HTML?&lt;/p&gt;  &lt;p&gt;So I thought that SQL Server HTTP Endpoints for SQL would be great thing to use to solve this problem.&amp;#160;&amp;#160; As all I was after was xml document to stream over HTTP.&amp;#160;&amp;#160; There was no business logic needed so all the .Net would be is just another layer acting as go between.&amp;#160; Also I didn’t what to waste time on what code which wouldn’t have added any value.&lt;/p&gt;  &lt;p&gt;So I created my stored procedure to produce an XML document that I found usable by using the For XML Path.&amp;#160; Then I started to look at how to create a HTTP endpoint for SOAP. After working through this I was presented with this message from my SQL Server 2008: &amp;quot;Creating and altering SOAP endpoints will be removed in a future version of SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use it.&amp;quot;&lt;/p&gt;  &lt;p&gt;It was nice to see that Microsoft are giving people plenty or warning about breaking changes for next version of SQL server.&amp;#160; It’s a surprise that a feature is being dropped so quick, second only to Notification Services since I have known the product, but I can understand the decision as a lot of questions on how, why&amp;#160; &amp;amp;&amp;#160; should it be used were ask by some of our SQL Server developers.&amp;#160;&amp;#160; So I took notice of Microsoft warning and tried to see if there was another method I could get my data into an XML document and streamed over HTTP without using .Net code and web services.&lt;/p&gt;  &lt;p&gt;All I was doing with this data was just reading for display via another component.&amp;#160; The data was in a structured format.&amp;#160;&amp;#160; Then I thought about Reporting Services, as you can write a report and get the reporting server to render to XML.&amp;#160;&amp;#160; So I quickly wrote a report to get the outputted xml into the format that I wanted.&amp;#160; Then in my static html I changed my http request to point to my report server with added option to render to XML.&lt;/p&gt;  &lt;p&gt;This approach did work and was great, as I managed to produce a page that could request data XML data and render data without any need to write .Net code.&amp;#160; The static html page would always remain up to date.&amp;#160; Another bonus was I had the report ready to show the data in a table from without having to re-write or reduplicating SQL code.&amp;#160; I was also then able to extend this to accept parameters so I could order the data base upon some user data from the HTML input control.&lt;/p&gt;  &lt;p&gt;Now this approach is not always going to work for every situation.&amp;#160; One reason is that reporting services security will not allow anonymous access.&amp;#160; So when using a windows security the report server would need to be on the same server.&amp;#160; A method to overcome this would be to create some forms authentication method on the report server and get your site to create the form cookie automatically. &lt;/p&gt;  &lt;p&gt;Another potential problem is way that Reporting Services sends the XML data other HTTP.&amp;#160; The XML data is actually sent as an attachment file on the HTTP response.&amp;#160; Now some applications, like the side bar gadgets, might not be allowed to, or can’t, handle http attachments.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-5322250190356323162?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/5322250190356323162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=5322250190356323162' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5322250190356323162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/5322250190356323162'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/06/could-http-soap-t-sql-endpoint-be.html' title='Could HTTP Soap / T-SQL endpoint be replaced by Reporting Services XML Reports?'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-6836132500095736820</id><published>2008-02-19T18:12:00.000Z</published><updated>2010-02-15T18:17:01.011Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='SfTS v2'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>How to E-mail the Sprint Burndown Chart to yourself or your team.</title><content type='html'>&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: Calibri;"&gt;I have been working on &lt;a href="http://scrumforteamsystem.com/" mce_href="http://scrumforteamsystem.com/" target="_blank"&gt;Scrum for Team System &lt;/a&gt;focusing on the reporting functionality of this tool.&amp;nbsp; One of the things I looked at was to get the reports delivered to me by e-mail.&amp;nbsp; I went looking to see if there was an interface via the Team Explorer interface, to which I found quickly there wasn’t.&amp;nbsp; However because TFS uses Reporting Services I knew that I could use Reporting Services subscriptions functionality.&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: Calibri;"&gt;Firstly, if not already configured, the Reporting Services server will need to will need to be set up to point to an SMTP server.&amp;nbsp; This can be done by using the Reporting Services configuration tool and updating the e-mail settings within this tool. &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: Calibri;"&gt;You can find this tool on your TFS server under the following: Start Menu &amp;gt; All Programs &amp;gt; Microsoft SQL Server 2005 &amp;gt; Configuration Tools&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;a href="http://lh5.ggpht.com/_CJNik6Tu6JU/S3mPAAbjlNI/AAAAAAAAABU/hsJTfSpL82Y/s1600-h/RS2005ConfigureEmail%5B8%5D.png" target="_blank"&gt;&lt;img alt="RS2005ConfigureEmail" border="0" height="174" src="http://lh4.ggpht.com/_CJNik6Tu6JU/S3mPA6QbXZI/AAAAAAAAABY/jwE6DCdEnvw/RS2005ConfigureEmail_thumb%5B6%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="RS2005ConfigureEmail" width="240" /&gt;&lt;/a&gt; &lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;a href="http://blogs.conchango.com/photos/conchango_bloggers/picture9800.aspx" mce_href="/photos/conchango_bloggers/picture9800.aspx" target="_blank"&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: Calibri;"&gt;To create the subscription you need to use the Report Manager &amp;nbsp;(to gain access to this you can right mouse click on the report folder within the team explorer): &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;a href="http://lh4.ggpht.com/_CJNik6Tu6JU/S3mPBc_F_NI/AAAAAAAAABc/wVFhGjIM1LA/s1600-h/TeamExplorer2008ShowReportSite%5B10%5D.png" target="_blank"&gt;&lt;img alt="TeamExplorer2008ShowReportSite" border="0" height="240" src="http://lh6.ggpht.com/_CJNik6Tu6JU/S3mPCMOAd6I/AAAAAAAAABg/wdgdj_JbGio/TeamExplorer2008ShowReportSite_thumb%5B8%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="TeamExplorer2008ShowReportSite" width="144" /&gt;&lt;/a&gt; &lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;a href="http://blogs.conchango.com/photos/conchango_bloggers/picture9801.aspx" mce_href="/photos/conchango_bloggers/picture9801.aspx" target="_blank"&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;a href="http://blogs.conchango.com/photos/conchango_bloggers/picture9801.aspx" mce_href="/photos/conchango_bloggers/picture9801.aspx" target="_blank"&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="margin: 0cm 0cm 10pt;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: Calibri;"&gt;When the report manager is loaded then the root folder will contains folders based upon the name of Team &amp;nbsp;Projects. Click on the folder that contains the required reports. After the list of reports have loaded click on the Sprint Burndown report to view the report.&amp;nbsp; After the report has rendered select the subscriptions tab, once the page has loaded and then click on new Subscriptions.&amp;nbsp; Then filling the necessary details on how the report should be delivered and what report parameters the report should used when it runs.&amp;nbsp; Finally I would recommend that for the parameters select the option to pick the defaults of the reports.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-6836132500095736820?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/6836132500095736820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=6836132500095736820' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6836132500095736820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/6836132500095736820'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/02/how-to-e-mail-sprint-burndown-chart-to.html' title='How to E-mail the Sprint Burndown Chart to yourself or your team.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_CJNik6Tu6JU/S3mPA6QbXZI/AAAAAAAAABY/jwE6DCdEnvw/s72-c/RS2005ConfigureEmail_thumb%5B6%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-7469911849357199034</id><published>2008-02-19T18:02:00.000Z</published><updated>2010-02-15T18:03:34.466Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum for Team System'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS2008'/><title type='text'>How to tell when the Team Foundation Server data warehouse was last updated.</title><content type='html'>&lt;p style="margin: 0cm 0cm 10pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;While I have been working on the &lt;a href="http://www.scrumforteamsystem.com" target="_blank"&gt;Scrum for Team System&lt;/a&gt; reporting I came across a re-occurring issue.&lt;span&gt;&amp;#160; &lt;/span&gt;The issue was not knowing when our data warehouse last updated or when the next update was due to happen.&lt;span&gt;&amp;#160; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 10pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;After some investigation, including some information from a link on one of my colleague’s &lt;a href="http://consultingblogs.emc.com/russellseymour/archive/2007/08/24/TFS_3A00_-Scrum-Burn-Down-Charts.aspx" target="_blank"&gt;blog posts&lt;/a&gt;, I found the answer to the issue.&lt;span&gt;&amp;#160; &lt;/span&gt;In the TFS &lt;span&gt;&amp;#160;&lt;/span&gt;data warehouse there is a table called: _WarehouseConfig.&lt;span&gt;&amp;#160; &lt;/span&gt;This contains some useful information like when the last data warehouse was last process time, process interval and end time of each step of the process ended.&lt;span&gt;&amp;#160;&amp;#160; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 10pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;So with this information I updated the version report for Scrum for Team System to include the following information: process interval time, next time process is due, last time the cube was processed, last time the data in data warehouse was updated.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 10pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;I have attached a copy of the new report as it not exclusive to Scrum for Team System.&lt;span&gt;&amp;#160; &lt;/span&gt;Also this report was written for TFS 2008.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-7469911849357199034?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/7469911849357199034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=7469911849357199034' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/7469911849357199034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/7469911849357199034'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2008/02/how-to-tell-when-team-foundation-server.html' title='How to tell when the Team Foundation Server data warehouse was last updated.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-1735969239152772305</id><published>2007-02-21T17:53:00.000Z</published><updated>2010-02-15T17:55:38.883Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Merge Replication'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>SQL Server 2005 Merge Replication not replicationing changes to the subscribers</title><content type='html'>&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;I have been using SQL Server 2005 merge replication within my current project.&amp;nbsp; It is a centralized Merge push topology using a custom RMO application with over 350 subscribers but that is the subject for another post…&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;While we have been testing there have been some issues raised by our testers and one of these in particular is what I’d like to write about today.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;We were seeing data being inserted by the application into the publisher database but this data was not being replicated down the to the targeted subscriber (parameterized filters were being used).&amp;nbsp; Bizarrely, all the changes made at the target subscriber were replicated up to the subscriber.&amp;nbsp; &lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;The data which was not being replicated turned out to be new child data organized by a join filter within the replication publication.&amp;nbsp; The application is a .net smart client which is used at both publisher and subscriber database and uses a SQL Server login account to access the database. After some investigation by me and my colleague, &lt;a href="http://consultingblogs.emc.com/JamesRowlandJones" target="_blank"&gt;James Rowland-Jones&lt;/a&gt;, we found the issue.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;Using SQL Server profiler to track all the SQL statements we traced the problem to the insert merge trigger.&amp;nbsp; The trigger was not assigning the child data to the correct partition i.e. no row being inserted into MSMERGE_CURRENT_PARTITION_MAPPINGS.&amp;nbsp; The problem was with the way the trigger checks for associated child records.&amp;nbsp; The trigger uses a generated replication view MSMERGE_REPL_VIEW_&amp;lt;PUBGUID&amp;gt;_&amp;lt;ARTGUID&amp;gt;, which rather than just performing a select on the base table to see if the data qualifies for a partition, it additionally performs a security check using an IsPalUser function. Our application user was not in the PAL and so consequently the view would return 0 results rather than the expected data.&amp;nbsp; This was certainly not what we were expecting!&amp;nbsp; The PAL is for controlling access to the publication not influencing what data is ultimately replicated.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;So to get the join filter to work as expected we had to add the application database user to the PAL.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="font-family: Arial, sans-serif; font-size: 10pt;"&gt;More on merge replication to follow….      &lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-1735969239152772305?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/1735969239152772305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=1735969239152772305' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1735969239152772305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/1735969239152772305'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/02/sql-server-2005-merge-replication-not.html' title='SQL Server 2005 Merge Replication not replicationing changes to the subscribers'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3148588332964388960</id><published>2006-12-20T17:50:00.000Z</published><updated>2010-02-15T17:50:57.060Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>MSBuild using SQL Script parameters</title><content type='html'>&lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;I have been working with MSBuild and the Microsoft.Sdc.Tasks to deploy my current project’s databases.&lt;span&gt;&amp;#160; &lt;/span&gt;Some of the SQL scripts that are executed within MSBuild need parameters to be set to create the database objects, which the Microsoft.Sdc.Tasks.Sql.Execute method supports.&lt;span&gt;&amp;#160; &lt;/span&gt;To use parameters within MSbuild and SQL.Execute; firstly create an item group (&amp;lt;ItemGroup&amp;gt;) then create element of any name as this will become the name of the item that can be referred to in MSbuild.&lt;span&gt;&amp;#160; &lt;/span&gt;Within the new element an attribute has to set called “Include”, then create two other elements called “name” and “value”.&lt;span&gt;&amp;#160; &lt;/span&gt;Here is an example:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&amp;lt;schemaName Include=”true”&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="text-indent: 36pt; margin: 0cm 0cm 0pt 36pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;name&amp;gt;@pTableName&amp;lt;/name&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="text-indent: 36pt; margin: 0cm 0cm 0pt 36pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;value&amp;gt;’sys.Objects’&amp;lt;/value&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&amp;lt;/schemaName&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&amp;lt;schemaTable Include=”true”&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="text-indent: 36pt; margin: 0cm 0cm 0pt 36pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;name&amp;gt;@pTableId&amp;lt;/name&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="text-indent: 36pt; margin: 0cm 0cm 0pt 36pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;value&amp;gt;342&amp;lt;/value&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&amp;lt;/ schemaTable &amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;The name element needs to be set to the name of the parameter including the @.&lt;span&gt;&amp;#160; &lt;/span&gt;The value element needs to be set with the value to which the parameter has to be set to. The only gotach I have found so far is that string data needs to wrapped in the quotes.&lt;span&gt;&amp;#160; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;Then to the get the MSBuild to pass the parameter into the Sql.Execute Task set a attribute on the task called Parameters and then @(&amp;lt;ItemName&amp;gt;).&lt;span&gt;&amp;#160; &lt;/span&gt;The Parameters will take in a list of parameters.&lt;span&gt;&amp;#160; &lt;/span&gt;Here is an example: &lt;span&gt;&amp;#160;&lt;/span&gt;&amp;lt;Sql.Execute Path=&amp;quot;CreateTable.sql&amp;quot; ServerName=&amp;quot;$(SQLServer)&amp;quot; DatabaseName=&amp;quot;$(Database)&amp;quot; Parameters=&amp;quot;@( schemaName);@( schemaTable)&amp;quot; /&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3148588332964388960?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3148588332964388960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3148588332964388960' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3148588332964388960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3148588332964388960'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/12/msbuild-using-sql-script-parameters.html' title='MSBuild using SQL Script parameters'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-2825861408221856523</id><published>2006-12-20T17:48:00.000Z</published><updated>2010-02-15T17:48:43.479Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTDB'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005 Team Edition for Database Professionals'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>To Collate or not to Collate</title><content type='html'>&lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;Collation plays an important role within the database, as it sets out how the SQL Server has to manage string data within storage &amp;amp; queries, yet I don’t script out the collation when scripting out my databases.&lt;span&gt;&amp;#160; &lt;/span&gt;So why don’t I script out the collation if it so important? Its because if the collation is specified but not used properly within the database it can cause some of most common problems, like “Cannot resolve collation conflict for EQUAL TO operation” or “Cannot resolve collation conflict for UNION operation”. These errors are caused when string data within different collations are being compared or combined into the same result set; this is nothing new so why talk about collation now? Well it’s to do with the release of Visual Studio 2005 Team Edition for Database Professionals (VSTDB) something I think needed to be taken in consideration if this is being used to manage the database side of the project. &lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;A cause for theses types of problem is when a table is created on a database with the collation scripted out and deployed on another database which has a different collation to the create script.&lt;span&gt;&amp;#160; &lt;/span&gt;With the VSTDB this will not occur as much because a project will be assigned a collation and the database will be created with this collation or if the database does not get recreated and has a different collation then the tables will be created with the project collation (This is the desired behavior when I saw this last and was confirmed when I spoke to the VSTDB Team in November). So I can see that VSTDB will help with reducing these types of errors.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;Another cause of the error is when creating temp tables without setting the collation to the same as the database collation and the server collation is different.&lt;span&gt;&amp;#160; &lt;/span&gt;There are 2 ways to resolve this issue. The first is to rebuild your system tables to match the collation of the database that has been created or another way is by using the collation clause within the create temp table script(s) within the T-SQL code.&lt;span&gt;&amp;#160; &lt;/span&gt;These errors could be become more frequent when using the VSTDB; because as mentioned before the database or tables that are create under the VSTDB are assigned the project collation, which will have to be of a type collation as there is no server default option and this could be different to that of the server that is being deployed to.&lt;span&gt;&amp;#160; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;By taking the time to put in the extra collation clause in the temp table script(s) it reduce the risk of database code failing with “cannot resolve collation” errors on any SQL server configuration.&lt;span&gt;&amp;#160; &lt;/span&gt;Also it reduce the temptation of people changing the VSTDB project collation to match there server collation if they can’t change their SQL server default collation and causing different behavior of SQL statements. &lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3" face="Times New Roman"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;I can understand the reason for making the database project ask for a collation because it means that when you unit test the code on any server it will always behave in the same way. Also it means as stated before, the database can run on any server with less risk of collation errors.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-2825861408221856523?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/2825861408221856523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=2825861408221856523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2825861408221856523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2825861408221856523'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/12/to-collate-or-not-to-collate.html' title='To Collate or not to Collate'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4043887766850225824</id><published>2006-12-20T17:43:00.000Z</published><updated>2010-02-15T17:44:42.404Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='.Net 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Delpoying Reporting Services Reports With MSBuild</title><content type='html'>&lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;I am currently responsible for deploying our project into the test and production environments.&lt;span&gt;&amp;#160; &lt;/span&gt;The project has a few reports which need to be installed on a few report servers.&lt;span&gt;&amp;#160; &lt;/span&gt;The deployment tool that I am using for the rest of my project is MSBuild so I tried to see if there was a way of getting MSBuild to deploy the reports.&lt;span&gt;&amp;#160; &lt;/span&gt;The only method that I found was to write an RS script file which deployed the reports and calls the Exec task to run the RS script.&lt;span&gt;&amp;#160;&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;So I started outright with RS script as I was not over joyed about writing VB.Net code as I am a C# coder. Then I remembered that MSBuild is customizable as it allows custom tasks to be written.&lt;span&gt;&amp;#160; &lt;/span&gt;So I stopped writing my VB.Net code went back C# and created a few tasks that are commonly needed to deploy: AddReportUser, CreateReportFolder, CreateConnectionSoruces, DeployReports and SetReportsDataSource.&lt;span&gt;&amp;#160; &lt;/span&gt;The task code was easy to write. I did have to change some of the auto generated code.&lt;span&gt;&amp;#160; &lt;/span&gt;I changed the refence.cs file by changing the ReportingService2005 method to accept a string as it called and removed all references to the setting file and app.config.&lt;span&gt;&amp;#160; &lt;/span&gt;I also deleted the setting file and app.config that was created by the Visual Studio.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4043887766850225824?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4043887766850225824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4043887766850225824' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4043887766850225824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4043887766850225824'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/12/delpoying-reporting-services-reports.html' title='Delpoying Reporting Services Reports With MSBuild'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4902943824483690235</id><published>2006-10-11T18:34:00.000+01:00</published><updated>2010-02-15T17:36:02.198Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Reporting Services Express Edition using host file redirect to connect to local database.</title><content type='html'>&lt;p style="margin: 0cm 0cm 0pt" class="MsoNormal"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span style="font-family: &amp;#39;Times New Roman&amp;#39;; font-size: 12pt"&gt;I had a few reports for an application that needed to be deployed to number of different report servers.&lt;span&gt;&amp;#160; &lt;/span&gt;The report servers were Express edition of Reporting Services 2005 with the application database on the same server which helped with the connection limitation of Reporting Services 2005 Express. As the report servers were joined to a domain their computer names have to be unique, the only way application was going to get around this problem was to use host file redirect.&lt;span&gt;&amp;#160; &lt;/span&gt;To help with deploying the report I was to going to try to use the host idea, so I added the server name to the localhost entry and tried to run the reports.&lt;span&gt;&amp;#160; &lt;/span&gt;Unfortunately this would not work because it looks like the reporting services 2005 express checks the name of the computer, which it gets from the following path HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\ComputerName\ActiveComputerName, against the datasource within the connection if they don’t match then raises an error.&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4902943824483690235?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4902943824483690235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4902943824483690235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4902943824483690235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4902943824483690235'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/reporting-services-express-edition.html' title='Reporting Services Express Edition using host file redirect to connect to local database.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4995453721684615389</id><published>2006-10-11T17:23:00.001+01:00</published><updated>2010-02-15T17:39:20.363Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Report Viewer Customizing Printing for Local Report</title><content type='html'>We had a requirement to allow a front page, which was another local report, to be printed before the report within the report viewer was printed.&amp;nbsp; As both reports were local reports it was easy to create a print button which allowed us to meet the requirements, here is the code that we used: &lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.printFrontingSheetCheckbox.Checked)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt; LocalReport frontsheet = front.reportViewer1.LocalReport;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt; Export(frontsheet, 8.27f, 11.69f, 0f, 0f, 0f, 0f);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt; m_currentPageIndex = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt; Print(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Stream s &lt;span class="kwrd"&gt;in&lt;/span&gt; m_streams)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;  s.Close();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt; front = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;LocalReport report = reportViewer.LocalReport;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;Export(report, 11.69f, 8.27f, 0f, 0f, 0f, 0f);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;m_currentPageIndex = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;Print(&lt;span class="kwrd"&gt;true&lt;/span&gt;); &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Stream s &lt;span class="kwrd"&gt;in&lt;/span&gt; m_streams)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt; s.Close();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Print(&lt;span class="kwrd"&gt;bool&lt;/span&gt; landscape)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (m_streams == &lt;span class="kwrd"&gt;null&lt;/span&gt; || m_streams.Count == 0)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt; PrintDocument printDoc = &lt;span class="kwrd"&gt;new&lt;/span&gt; PrintDocument();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt; PrinterSettings ps = &lt;span class="kwrd"&gt;new&lt;/span&gt; PrinterSettings();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt; ps.PrinterName = printDialog1.PrinterSettings.PrinterName;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt; ps.DefaultPageSettings.Landscape = landscape;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    ps.DefaultPageSettings.PrinterSettings.DefaultPageSettings.Landscape = landscape;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt; printDoc.PrinterSettings = ps;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (!printDoc.PrinterSettings.IsValid)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt; {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;  &lt;span class="kwrd"&gt;string&lt;/span&gt; msg = String.Format(&lt;span class="str"&gt;"Can't find printer \"{0}\"."&lt;/span&gt;, printDialog1.PrinterSettings.PrinterName);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;  MessageBox.Show(msg, &lt;span class="str"&gt;"Print Error"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt; }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt; printDoc.PrintPage += &lt;span class="kwrd"&gt;new&lt;/span&gt; PrintPageEventHandler(PrintPage);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt; printDoc.Print();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;} &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;&lt;span class="rem"&gt;/// Export the given report as an EMF (Enhanced Metafile) file.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Export(LocalReport report, &lt;span class="kwrd"&gt;float&lt;/span&gt; PageWidth, &lt;span class="kwrd"&gt;float&lt;/span&gt; PageHeight, &lt;span class="kwrd"&gt;float&lt;/span&gt; MarginTop, &lt;span class="kwrd"&gt;float&lt;/span&gt; MarginLeft, &lt;span class="kwrd"&gt;float&lt;/span&gt; MarginRight, &lt;span class="kwrd"&gt;float&lt;/span&gt; MarginBottom)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt; StringBuilder deviceInfosb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="str"&gt;"&amp;lt;DeviceInfo&amp;gt;"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="str"&gt;"&amp;lt;OutputFormat&amp;gt;EMF&amp;lt;/OutputFormat&amp;gt;"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;PageWidth&amp;gt;{0}in&amp;lt;/PageWidth&amp;gt;"&lt;/span&gt;, PageWidth)); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;PageHeight&amp;gt;{0}in&amp;lt;/PageHeight&amp;gt;"&lt;/span&gt;, PageHeight));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;MarginTop&amp;gt;{0}in&amp;lt;/MarginTop&amp;gt;"&lt;/span&gt;, MarginTop));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;MarginLeft&amp;gt;{0}in&amp;lt;/MarginLeft&amp;gt;"&lt;/span&gt;, MarginLeft));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;MarginRight&amp;gt;{0}in&amp;lt;/MarginRight&amp;gt;"&lt;/span&gt;, MarginRight));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;MarginBottom&amp;gt;{0}in&amp;lt;/MarginBottom&amp;gt;"&lt;/span&gt;, MarginBottom));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt; deviceInfosb.Append(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&amp;lt;/DeviceInfo&amp;gt;"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; deviceInfo = deviceInfosb.ToString();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt; Microsoft.Reporting.WinForms.Warning[] warnings;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt; m_streams = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Stream&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt; report.Render(&lt;span class="str"&gt;"Image"&lt;/span&gt;, deviceInfo, CreateStream, &lt;span class="kwrd"&gt;out&lt;/span&gt; warnings);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Stream stream &lt;span class="kwrd"&gt;in&lt;/span&gt; m_streams)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;  stream.Position = 0;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;}&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;&lt;span class="rem"&gt;/// Handler for PrintPageEvents&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PrintPage(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, PrintPageEventArgs ev)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  75:  &lt;/span&gt; Metafile pageImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Metafile(m_streams[m_currentPageIndex]);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  76:  &lt;/span&gt; ev.Graphics.DrawImage(pageImage, ev.PageBounds);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt; m_currentPageIndex++;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  78:  &lt;/span&gt; ev.HasMorePages = (m_currentPageIndex &amp;lt; m_streams.Count);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  79:  &lt;/span&gt;} &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then a new requirement came that we needed to get the report viewer print button to be the same as our print button.&amp;nbsp; At first I didn’t think it was possible because the button was within the report viewer control, but after looking through all the properties, methods and events we found the print event, which according to the object help, fires after the user prints a report.&amp;nbsp; This would help because at least we would be able to detect a print event and then print the front page at the end of printing the report.&amp;nbsp; But a collogue played around with the code and found that the event gets fired first before the printing happens and setting the cancel variable to true stops the report viewer doing the printing then by calling our printing code this allowed us to meet all the requirements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4995453721684615389?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4995453721684615389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4995453721684615389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4995453721684615389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4995453721684615389'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/report-viewer-customizing-printing-for.html' title='Report Viewer Customizing Printing for Local Report'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-4063181479142894740</id><published>2006-09-14T18:46:00.001+01:00</published><updated>2010-02-12T18:57:13.267Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Dynamic SQL Server ordering without using dynamic SQL.</title><content type='html'>For my current project I have a stored procedure that needs to sort data by 1 of 3 columns depending upon the option chosen by the user from the application.&amp;nbsp; This is only the dynamic part of the stored procedure, which also happens to be very complicated, so I didn’t wish to use dynamic SQL Server.&amp;nbsp; I know that within SQL server 2000 you can use a case against a variable to select which column to order the data by but the only caveat is that all the columns have to be the same data type.&amp;nbsp; My problem was that not all my columns are the same data type, I managed to over come this by using the new function within SQL server 2005 call Row_Number(), which gives a row number to each row, based upon the order by used within the over function, as this always returns the same data type it can be used within the case statement for the ordering. Below is an example of code:   &lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;1:&lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vOrderby &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;SET&lt;/span&gt; @vOrderby = 4&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; TABLE_CATALOG , TABLE_SCHEMA , TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; information_schema.columns &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; &lt;span class="kwrd"&gt;CASE&lt;/span&gt; @vOrderby  &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; 1 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; TABLE_SCHEMA, TABLE_NAME) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; 2 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; COLUMN_NAME) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; 3 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; DATA_TYPE) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; 4 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; ORDINAL_POSITION) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; 5 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; IS_NULLABLE) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; -1 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; TABLE_SCHEMA &lt;span class="kwrd"&gt;DESC&lt;/span&gt; , TABLE_NAME &lt;span class="kwrd"&gt;DESC&lt;/span&gt; ) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; -2 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; COLUMN_NAME &lt;span class="kwrd"&gt;DESC&lt;/span&gt; ) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; -3 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; DATA_TYPE &lt;span class="kwrd"&gt;DESC&lt;/span&gt; ) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; -4 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; ORDINAL_POSITION &lt;span class="kwrd"&gt;DESC&lt;/span&gt; ) &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; -5 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; IS_NULLABLE &lt;span class="kwrd"&gt;DESC&lt;/span&gt;) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&lt;span class="kwrd"&gt;END&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I am not recommending this as a good solution, just a solution that might be useful for a small database.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-4063181479142894740?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/4063181479142894740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=4063181479142894740' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4063181479142894740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/4063181479142894740'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/dynamic-sql-server-ordering-without.html' title='Dynamic SQL Server ordering without using dynamic SQL.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-243074089443004902</id><published>2006-08-16T13:14:00.000+01:00</published><updated>2010-02-12T18:29:07.223Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Reporting Services Report Viewer Control &amp; Page Sizes</title><content type='html'>I have found that the reporting services report viewer control might not use the correct paper size to render the report.&amp;nbsp; The reason for this can be found on the following link: &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PageIndex=1&amp;amp;SiteID=1&amp;amp;PostID=126378"&gt;click here&lt;/a&gt;. Quick summary of the solution is that if you wish the report viewer control to render A4 page size instead of Letter then within the report define the pages size of A4 in inches.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-243074089443004902?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/243074089443004902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=243074089443004902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/243074089443004902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/243074089443004902'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/reporting-services-report-viewer.html' title='Reporting Services Report Viewer Control &amp;amp; Page Sizes'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-115167222755950440</id><published>2006-06-30T13:54:00.001+01:00</published><updated>2010-02-12T17:55:18.654Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Avery Labels Printing via RDL / Reporting Services</title><content type='html'>I have just managed to solve the problem of how to give an application the ability to print Avery labels with data from our database. I only had to support two label formats (L7161 and L7163) and the data requirement was static as well. So I looked at RDL / Reporting Services and the Report Viewer control. &lt;br /&gt;&lt;br /&gt;The way I wrote the report is as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Set the page size to A4 and all the margins to 0cm.&lt;/li&gt;&lt;li&gt;Made sure that the report was not using a Header or Footer.&lt;/li&gt;&lt;li&gt;Placed one list control per column of labels on a sheet&lt;/li&gt;&lt;li&gt;Changed the size of the list control to be the same as a single label&lt;/li&gt;&lt;li&gt;Then set an expression on the list visibility based on the result of the rownumber modulus by the number of columns (making sure each column looked for a unique result)&lt;/li&gt;&lt;li&gt;Then added the textboxes for the data making sure there was a gap between the top and bottom of the list control. Also made sure that the text boxes didn’t push the list box size out.&lt;/li&gt;&lt;/ul&gt;I did have trouble trying to line the labels up 100% also using this approach does have some draw backs like updating will become a hard task and the use of the labels will be locked for one use only.&lt;br /&gt;&lt;br /&gt;But now I have a template it should not be long before I will write Avery label component using RDL&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-115167222755950440?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/115167222755950440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=115167222755950440' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/115167222755950440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/115167222755950440'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/06/avery-labels-printing-via-rdl.html' title='Avery Labels Printing via RDL / Reporting Services'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-3857090550454683450</id><published>2006-04-16T18:58:00.000+01:00</published><updated>2010-02-15T17:59:20.899Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Merge Replication'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>SQL Server 2005 Merge Replication Subscriber unexpectedly deleting during data Synchronisation.</title><content type='html'>&lt;p&gt;Within my current project I have been using SQL Server 2005 merge replication.&amp;#160; While I have been testing some issues have been raised by our testers and I would like to write about another one of these in particular.&lt;/p&gt;  &lt;p&gt;Data, which was entered at the subscriber, was being removed while synchronizing with the publisher.&amp;#160; This can happen when the data entered isn’t part of the partition for a given subscriber.&amp;#160; However, on this occasion we expected the data to remain in place.&amp;#160; After some investigation by me and my colleague, &lt;a href="http://consultingblogs.emc.com/JamesRowlandJones/" target="_blank"&gt;James Rowland-Jones&lt;/a&gt;, we found the issue.&lt;/p&gt;  &lt;p&gt;We noted that the affected tables were organised in parent child relationships at a table / schema level but they were joined child parent in the replication topology.&amp;#160; They were joined via a join filter with a partition filter on the child record.&amp;#160; So Customers 1 -&amp;gt; N Orders but partitioned On Orders with a join filter back to Customers.&amp;#160; The topology was created in this way to help partition the data sent to the individual subscribers i.e. a subscriber would only see customers that it had created orders for.&lt;/p&gt;  &lt;p&gt;To troubleshoot the problem we used SQL Server profiler to track all the SQL statements used in a synchronization session.&amp;#160; We found that the issue was to due to the synchronization process and how it processed the records sent from the subscriber.&amp;#160; &lt;/p&gt;  &lt;p&gt;When the subscriber has data entered it doesn’t evaluate or set its current partition mapping. The mappings are worked out dynamically during the synchronization process.&amp;#160; Only the data in MsMerge_Contents is sent to the publisher for evaluation.&amp;#160; Whilst working this out the process does not take into account the fact that a child record at a data level was a parent with the partitioning key in the topology.&amp;#160; During the replication process the articles were processed in foreign key relationship order so the parent data was being added first. A check was then being made to see what partition this data belonged to.&amp;#160; As the child data had not yet been evaluated the partitioning data wasn’t available so the topology sent a delete back to the subscriber.&lt;/p&gt;  &lt;p&gt;The way to resolve this was to enforce the processing order manually. We had to make a change to the database and replication.&amp;#160; The change to the database was to set NOT FOR REPLICATION on all foreign keys.&amp;#160; We also changed the topology to enforce processing order within replication. In TSQL you’d do this by setting the @processing_order parameter in sp_addmergearticle. Unfortunately in RMO this could not be set via a property or method.&amp;#160; I had to create a T-SQL statement to call sp_changemergearticle to update the processing order after the articles were created.&lt;/p&gt;  &lt;p&gt;However, there is a gotcha to watch out for with this approach as well.&amp;#160; As soon as one starts setting the processing order manually you need to set it for all objects.&amp;#160; This is because any object without an explicit number will be evaluated before those that have. So the rule is: when enforcing a processing order you will need to enforce it for all objects: Tables, Views, Procedures and Functions.&amp;#160; &lt;/p&gt;  &lt;p&gt;There are two basic approaches to setting up the processing order.&amp;#160; The first is to give all objects a unique number.&amp;#160; The second is to give all object types a unique number.&amp;#160; We went for the latter as we thought it’d be simpler to manage overall. It would also allow us to set big bands or ranges to allow for future changes.&amp;#160; However, we had to also make sure we processed the replication joins in a set order.&amp;#160; Therefore within the tables we gave another higher number in the range to each level of join.&amp;#160;&amp;#160; Tables at the top of the replication tree were 10000 the tables they had join filters to were 20000 and so on. When we hit dependencies within objects we simply gave them another range.&amp;#160; We hit this with functions that referenced other functions.&lt;/p&gt;  &lt;p&gt;Once we’d set the processing order correctly and set NOT FOR REPLICATION on all the foreign keys everything worked and we were able to return the issue as fixed back to the testers -&amp;#160; which was nice. I should also point out that we did try just changing the NOT FOR REPLICATION option only but this didn’t work for us. We had to make both changes for this to work.    &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-3857090550454683450?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/3857090550454683450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=3857090550454683450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3857090550454683450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/3857090550454683450'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/04/sql-server-2005-merge-replication.html' title='SQL Server 2005 Merge Replication Subscriber unexpectedly deleting during data Synchronisation.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-114310558144365005</id><published>2006-03-23T09:12:00.001Z</published><updated>2010-02-12T17:54:50.207Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Installing SQL Server 2005 Express with Remote Connections.</title><content type='html'>I have managed to set-up a SQL Server 2005 Express instance, on a windows-XP machine, with remote connections enable. The actual installation of the SQL Server 2005 express instance was straightforward, but enabling the remote connections was problematic.&lt;br /&gt;I found that I was not the only person. In the end I found these steps worked for me:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Open up the SQL Server Surface Area Configuration Manager&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Click on Surface Area configurations for services and connections.&lt;/li&gt;&lt;li&gt;Click the remote Connections entry on the tree, select local and remote connections (TCP/IP) . Click OK.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Open the SQL Server Configuration Manager&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Select SQL Server 2005 Network Configuration/Protocols for the instance.&lt;br /&gt;Right click TCP/IP, select properties.&lt;/li&gt;&lt;li&gt;Click the IP Addresses tab, change the Enable flag on the IP addresses to YES.&lt;/li&gt;&lt;li&gt;In the IPAll section, copy the port value of the TCP Dynamic Ports to the TCP Port.&lt;/li&gt;&lt;li&gt;Clear the TCP Dynamic Port value.&lt;/li&gt;&lt;li&gt;Click Okay.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Open up Control Panel/Firewall.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Click Exceptions tab.&lt;/li&gt;&lt;li&gt;Click add port button.&lt;/li&gt;&lt;li&gt;Enter the TCP port number specified in the IPAll/TCP Port section above.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Restart the SQL Server Service instance.&lt;/li&gt;&lt;li&gt;Restart the SQL Server Browser Service.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-114310558144365005?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/114310558144365005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=114310558144365005' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114310558144365005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114310558144365005'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/03/installing-sql-server-2005-express.html' title='Installing SQL Server 2005 Express with Remote Connections.'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-114235118105421597</id><published>2006-03-14T15:44:00.001Z</published><updated>2010-02-12T17:54:34.402Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>SSIS Creating Synchronous Transform Component</title><content type='html'>Do you need to write a custom component to transform input data, and disregard this input data, instead, replacing it?&lt;br /&gt;That's was what I needed to accomplish with my component. It takes data from the input buffer and performs a lookup via an external API. If there is a match, send the result data down a "match" output otherwise send the input data down a "unmatch" output. The key here is that the "shape" of the output was changing. In other words, the metadata of the output was very different from that of the input.I also want my component to be synchronous (meaning synchronous, I mean that the component takes a row, processes it and then immediately sends it down an output) and not asynchronous (meaning that it reads all the data and then processes the data in an internal buffer). Now from what I was reading and seeing this was what I thought SSIS meant by synchronous and asynchronous components, but I was wrong! &lt;br /&gt;&lt;ol&gt;&lt;li&gt;An asynchronous component can eitherRead all the data in the buffer and cache it. Then after reading all the records process them and then send the data out or &lt;/li&gt;&lt;li&gt;It can read a row of the input; process that data in place without caching it and then send it down the output. &lt;/li&gt;&lt;/ol&gt;So, I wrote my component to be an asynchronous component but behave like a synchronous component. To do this I create my component outputs setting one to be a synchronous by setting SynchronousInputID of the "unmatch" output to equal the InputId of the input, and for the "matched" output setting InputId=0. The PrimeOutput() method simply needs to assign the output buffer to a private variable. Then, in ProcessInput(), read the row, process it using the external API, and then add the row straight into the output buffer. If you would like to see more, here is the post that I placed on the forum that helped to solve my probelm &lt;a href="http://forums.microsoft.com/MSDN/showpost.aspx?postid=295247&amp;amp;siteid=1&amp;amp;message_id=138175&amp;amp;notification_id=138175"&gt;http://forums.microsoft.com/MSDN/showpost.aspx?postid=295247&amp;amp;siteid=1&amp;amp;message_id=138175&amp;amp;notification_id=138175&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-114235118105421597?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/114235118105421597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=114235118105421597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114235118105421597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114235118105421597'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/03/ssis-creating-synchronous-transform.html' title='SSIS Creating Synchronous Transform Component'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-114131788120315414</id><published>2006-03-02T16:40:00.001Z</published><updated>2010-02-12T17:53:18.566Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><title type='text'>SSIS File handle leak in For Each Loop</title><content type='html'>I am currently working on a project which needs to load over a 1000 xml files. The files are stored across 10 subfolders. I am using a foreach loop with a file enumerator, which is configured at the top of the folder structure and traverses the subfolders. This loops through the files, load the data and then moves the file to another folder. The package executes fine for a few 100 files but then hangs; this happens after a different number of processed files each time the package is run. While trying to resolve the problem we ran performance counters and noticed that the number open handles increased significantly just about the time Dtexec looked like it had hanged and DTexec also then started taking a lot of the cpu processing time.&lt;br /&gt;&lt;br /&gt;Update: I put this on the Microsoft forums and got a intresting answer back &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=277765&amp;amp;SiteID=1"&gt;See Here&lt;/a&gt;;&lt;br /&gt;There seems to be a memory leak with foreach loop which should be fixed in sp1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-114131788120315414?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/114131788120315414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=114131788120315414' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114131788120315414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114131788120315414'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/03/ssis-file-handle-leak-in-for-each-loop.html' title='SSIS File handle leak in For Each Loop'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-114063054273829736</id><published>2006-02-22T17:48:00.001Z</published><updated>2010-02-12T17:53:03.008Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><title type='text'>SSIS Connection Object and Expressions</title><content type='html'>I have been writing a custom source adapter that uses a file connection within the connection manager. If I hard-code a specific file then the component works. However if I use a file connection that has an expression defined which updates the connection, for example when you have a for-each loop looping over a set files. The file connection doesn’t seem to re-evaluate expression each time you access the file connection via the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-114063054273829736?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/114063054273829736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=114063054273829736' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114063054273829736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/114063054273829736'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/02/ssis-connection-object-and-expressions.html' title='SSIS Connection Object and Expressions'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-113949640590086813</id><published>2006-02-09T14:46:00.001Z</published><updated>2010-02-12T17:52:08.669Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><title type='text'>SSIS Variable Deadlock</title><content type='html'>I have noticed a problem with the script task within SSIS. The problem occurs when a script task encounters an error and the SSIS on-error event also has a script task that uses a variable that is being locked by the script task that raised the error. The problem seems to be that the SSIS on-error event fires and runs before the script task that raised the error has finished and released its lock on the variable. I have even tred to overcome this problem by using a try/catch block to release the variable locks but this also failed to resolve the problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-113949640590086813?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/113949640590086813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=113949640590086813' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113949640590086813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113949640590086813'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/02/ssis-variable-deadlock.html' title='SSIS Variable Deadlock'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-113949637586849399</id><published>2006-02-09T14:45:00.001Z</published><updated>2010-02-12T17:51:47.506Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><title type='text'>SSIS Changes Database Settings</title><content type='html'>I have a SSIS package with a simple data flow task, which takes data from a flat file and loads it to an OLE-DB destination (which is configured to use Native OLE-DB\Native Client). As I ran the package via the command-line I noticed that SSIS made changes to the database options. One of the most important options that were being changed was the database recovery model which was modified to run under Bulk-Logged. This changing of the recovery model could cause problems for the back-up and recovery procedure if you are using incremental transaction log back-up as Bulk-Logged will not allow this to run. I can understand why SSIS makes this change because Bulk-Logged does not write any data to the transaction log for Bulk operations. For this reason it does not allow incremental log back-ups and always recommends that you do a back-up of the database when you change back to Simple or Full mode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-113949637586849399?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/113949637586849399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=113949637586849399' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113949637586849399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113949637586849399'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/02/ssis-changes-database-settings.html' title='SSIS Changes Database Settings'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-113777843306307859</id><published>2006-01-20T17:08:00.001Z</published><updated>2010-02-12T17:51:27.327Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>SSIS XML Task / Source Adapter</title><content type='html'>I have been working with SSIS using the XML Task and XML Source Adapter. I was getting an error say that an element is was not defined. When I check the XSD, which was using import / include schemas, I found the element was difined but not in the main XSD schema the adapter was pointing to but another schema which was being imported. The probelm was with the schema were the element was defined not being invaild for the XML Source Adapter, that was the real probelm, as soon as I corrected the imported schema the error was resolved.&lt;br /&gt;&lt;br /&gt;The probelm with the imported XSD schema there was some DTD define at the being of the file and XML Source Adapter does not support a mixture of DTD and XSD.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-113777843306307859?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/113777843306307859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=113777843306307859' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113777843306307859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113777843306307859'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/01/ssis-xml-task-source-adapter.html' title='SSIS XML Task / Source Adapter'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-113777234438064522</id><published>2006-01-20T15:52:00.001Z</published><updated>2010-02-12T17:49:27.772Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><title type='text'>SSIS Execute SQL Task With VARCHAR(MAX)</title><content type='html'>While I was using the SSIS Execute SQL Task to return a single row result I getting the following error:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="font-size: 85%;"&gt;[Execute SQL Task] Error: An error occurred while assigning a value to variable "RestoreCmd": "The type of the value being assigned to variable "User::RestoreCmd" differs from the current variable type. Variables may not change type during execution. Variable types are strict, except for variables of type Object!."&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size: 0px;"&gt;This was happening becuase I was trying to assgin a varchar(max) result column to SSIS string variable. &lt;/span&gt;&lt;br /&gt;There are two ways to solve this problem; one is to change the SSIS variable to object and convert each time it used to a string; the second way to solve this is to cast result column to max size limit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-113777234438064522?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/113777234438064522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=113777234438064522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113777234438064522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113777234438064522'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/01/ssis-execute-sql-task-with-varcharmax.html' title='SSIS Execute SQL Task With VARCHAR(MAX)'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-113776394662403501</id><published>2006-01-20T13:31:00.003Z</published><updated>2010-02-12T17:47:41.840Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Integration Services'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>SSIS 2005 and Database Snapshots</title><content type='html'>I have been looking into the feasibility of using database snapshots as method of rolling back an SSIS package that fails and this is what I found:&lt;br /&gt;Creating a database snapshot was not a real problem, there is one issue that you need to be aware of. For each data file within the database that the snapshot is being based on there will have to be a sparse file created for it. I have created a little SQL script that automates the creation of the database snapshot.&lt;br /&gt;&lt;br /&gt;Rolling back a database to its initial state after a package has errorred is a problem. The method to revert a database back to its initial state with database snapshots is a restore operation. The restore is a full restore, which of course means there can't be any connections while the restore is happening and this can't be done on-line because it might have to take out the primary data file. This is a problem because SSIS connection manager will create connections to the database when the package starts and doesn't release the connections until the package has completed its run.&lt;br /&gt;&lt;br /&gt;A SQL script that automates the creation of the database snapshot.&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vDBName &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(255) &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vFiles &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(&lt;span class="kwrd"&gt;MAX&lt;/span&gt;)&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @vSQLCmd &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(&lt;span class="kwrd"&gt;MAX&lt;/span&gt;) &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @vDBName = DB_NAME(), @vFiles = &lt;span class="str"&gt;''&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @vFiles = @vFiles + &lt;span class="str"&gt;'(Name = '&lt;/span&gt; + Name +&lt;span class="str"&gt;', filename='&lt;/span&gt;&lt;span class="str"&gt;''&lt;/span&gt;+ &lt;span class="kwrd"&gt;LEFT&lt;/span&gt;(physical_name,LEN(physical_name) - CHARINDEX(&lt;span class="str"&gt;'.'&lt;/span&gt;,REVERSE(physical_name))) + &lt;span class="str"&gt;'_PrePublish.ss'&lt;/span&gt;&lt;span class="str"&gt;'), '&lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; sys.database_filesWHERE TYPE = 0&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;SET&lt;/span&gt; @vSQLCmd = &lt;span class="str"&gt;'CREATE DATABASE '&lt;/span&gt; + @vDBName +&lt;span class="str"&gt;'_PrePublish ON '&lt;/span&gt; + &lt;span class="kwrd"&gt;LEFT&lt;/span&gt;(@vFiles,len(@vFiles)-2) + &lt;span class="str"&gt;' AS SNAPSHOT OF '&lt;/span&gt; + @vDBName&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;EXEC&lt;/span&gt;(@vSQLCmd);&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-113776394662403501?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/113776394662403501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=113776394662403501' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113776394662403501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/113776394662403501'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2006/01/ssis-2005-and-database-snapshots.html' title='SSIS 2005 and Database Snapshots'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-2178000162670752718</id><published>2005-02-11T13:24:00.001Z</published><updated>2010-02-12T18:48:56.729Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2005'/><title type='text'>Reporting Services Report Viewer using SQL Authentication</title><content type='html'>I have written some code, which will create a report and deploys it to a report server. However the connection string for the report has to use SQL Authentication. My code which builds the reports uses the same approach that Microsoft does to SQL Authentication within report, which is to not store the UserID and Password, so what would happen now when the report is displayed in the report viewer is that a prompt would appear asking for a username and password. This behavior had to be suppressed, because I did not wish the users to know or need to type in a userid or a password, so I tried to resolved this by looking for a way to get the connection string stored on the server when deploying the report, like you can when you use SQL Server Business Intelligence Development Studio, with no joy. I did find a solution with the Report Viewer control, there is method to send the data source credentials to the server without the user having to type them in. Below is an example: &lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;rvReporting.ServerReport.ReportServerUrl = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"Http://localhost/reportServer"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;rvReporting.PromptAreaCollapsed = &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;rvReporting.ShowProgress = &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;rvReporting.ServerReport.ReportPath =&lt;span class="str"&gt;"DemoReport"&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;Microsoft.Reporting.WinForms.DataSourceCredentials dataSourceCredentials = &lt;span class="kwrd"&gt;new&lt;/span&gt; Microsoft.Reporting.WinForms.DataSourceCredentials(); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;dataSourceCredentials.Name = &lt;span class="str"&gt;"ReportDataSource"&lt;/span&gt;; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;SqlConnectionStringBuilder str = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings[&lt;span class="str"&gt;"Concord"&lt;/span&gt;].ConnectionString); &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;dataSourceCredentials.UserId = str.UserID; &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;dataSourceCredentials.Password = str.Password; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;rvReporting.ServerReport.SetDataSourceCredentials(&lt;span class="kwrd"&gt;new&lt;/span&gt; Microsoft.Reporting.WinForms.DataSourceCredentials[1] { dataSourceCredentials }); rvReporting.RefreshReport();&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-2178000162670752718?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/2178000162670752718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=2178000162670752718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2178000162670752718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/2178000162670752718'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2010/02/reporting-services-report-viewer-using.html' title='Reporting Services Report Viewer using SQL Authentication'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-110270321839784715</id><published>2004-12-10T18:26:00.001Z</published><updated>2010-02-12T17:44:20.438Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Multithreading'/><title type='text'>Createing threads for a windows form</title><content type='html'>I am wrining a program that has lenghtly process which si casing my UI to freeze. I now how to the solve the probelm which is create thread and let it do the processing. Now this new ground for me so I went looking for some explames on how to this and I found this link &lt;a href="http://www.codeguru.com/Csharp/Csharp/cs_misc/userinterface/article.php/c4255/"&gt;CodeGuru: Maintaining a Responsive UI&lt;/a&gt;, which I found easy to follow, that explains about UI thread and some of the probelms that can happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-110270321839784715?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/110270321839784715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=110270321839784715' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/110270321839784715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/110270321839784715'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/12/createing-threads-for-windows-form.html' title='Createing threads for a windows form'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-110235469664752561</id><published>2004-12-06T17:13:00.002Z</published><updated>2010-02-12T17:43:58.540Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='DTS'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>DTS  Custom Tasks written .Net</title><content type='html'>After writing some custom task in VB6 for a client thought it would be better if they were in .Net. So after some research finding that it can be done I start re-writing them for .Net. I started running into some issues: &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Could not register custom task within the DTS client. This because Regasm does not expose the DLL entry point for DllRegisterServer, to solve this I had to write some extra code that will register the task in DTS.&lt;/li&gt;&lt;li&gt;The task then could not be use within DTS. This was because the default create interface was incorrect by the fact there was read-only function which dts does not like, I had disable the creation of default interface and write my own version.&lt;/li&gt;&lt;li&gt;The global variables not working after the .Net custom component set the values. This was some quirk between .Net and DTS as soon as try setting the value through the objects properties The activex script task and other tasks could not access the global variable. I mange to solve this deleting the Global variable and recreating it.&lt;/li&gt;&lt;/ul&gt;The main problem that can't be resolve is when running the these custom task there is a possible error that could happen (more so on a mutli-processor server) is the Virtual Runtime Error. The runtime error I was gettting was trying to call a function form object that no longer exist; this happens because between .Net and DTS the ownership of the object is losted and things get clear when they should not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-110235469664752561?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/110235469664752561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=110235469664752561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/110235469664752561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/110235469664752561'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/12/dts-custom-tasks-written-net.html' title='DTS  Custom Tasks written .Net'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-109947818541119496</id><published>2004-11-03T09:44:00.001Z</published><updated>2010-02-12T17:42:51.419Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSRS 2000'/><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services 2000'/><title type='text'>Reporting Services 2000</title><content type='html'>I have been using reporting services for a while now and I've found it to be a useful tool for application development. The reason for this I am working on web application that had some summary data which need to be display with the option to allow detail data to be seen. Also there was a requirement to exporting the data to spreadsheet, generate some charts displays to make application look sexy and give users quick and easy status reports to read. The application is using Object Model approach so instead writing code and creating pages. I sold reporting service to the client and I manage to give all the requirements need with in matter of days. It was easy to use, Easy to install and easy to manage as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-109947818541119496?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/109947818541119496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=109947818541119496' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/109947818541119496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/109947818541119496'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/11/reporting-services.html' title='Reporting Services 2000'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-109939087484042734</id><published>2004-11-02T10:21:00.001Z</published><updated>2010-02-12T17:41:52.459Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Multithreading'/><title type='text'>Multithreading .Net C#</title><content type='html'>Here is a list of articles that makes threading sound easy to do: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.csharpcorner.com/Code/2002/April/MtP1MtVsMt.asp"&gt;Multithreading Part I: Multithreading and Multitasking&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.c-sharpcorner.com/Code/2002/April/System.Threading.ThreadMT2.asp"&gt;Multithreading Part 2: Understanding the System.Threading.Thread Class&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.c-sharpcorner.com/Code/2002/April/MultithreadingP3.asp"&gt;Multithreading Part 3: Thread Synchronization&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.c-sharpcorner.com/Code/2002/April/MtP4MtVsMt.asp"&gt;Multithreading Part 4: The ThreadPool, Timer Classes and Asynchronous Programming Discussed&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-109939087484042734?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/109939087484042734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=109939087484042734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/109939087484042734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/109939087484042734'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/11/multithreading.html' title='Multithreading .Net C#'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-108963633652907398</id><published>2004-07-12T13:45:00.001+01:00</published><updated>2010-02-12T17:40:53.942Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='DBA'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>The future role of a DBA in Middle to Small Companys</title><content type='html'>&lt;a href = "http://www.winnetmag.com/SQLServer/Article/ArticleID/43155/SQLServer_43155.html"&gt;This is a link about the futre role of a DBA.&lt;/a&gt; Also people thoughts about the article are at the end of the piece.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-108963633652907398?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/108963633652907398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=108963633652907398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/108963633652907398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/108963633652907398'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/07/future-role-of-dba-in-middle-to-small.html' title='The future role of a DBA in Middle to Small Companys'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7476247.post-108869521561509733</id><published>2004-07-01T16:20:00.002+01:00</published><updated>2010-02-12T15:51:54.114Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Parts'/><category scheme='http://www.blogger.com/atom/ns#' term='Shareport'/><title type='text'>Developing Web Parts for SharePoint Portal Server 2003 in .NET</title><content type='html'>&lt;a href="http://www.devx.com/dotnet/Article/17518/0/page/5"&gt;Developing Web Parts for SharePoint Portal Server 2003 in .NET&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7476247-108869521561509733?l=zogamorph.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zogamorph.blogspot.com/feeds/108869521561509733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7476247&amp;postID=108869521561509733' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/108869521561509733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7476247/posts/default/108869521561509733'/><link rel='alternate' type='text/html' href='http://zogamorph.blogspot.com/2004/07/developing-web-parts-for-sharepoint.html' title='Developing Web Parts for SharePoint Portal Server 2003 in .NET'/><author><name>Steve Wright</name><uri>http://www.blogger.com/profile/15679255693378492813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_CJNik6Tu6JU/S3QHOEvlKDI/AAAAAAAAAAM/YCgFnleQAdQ/S220/avatarpic-l.png'/></author><thr:total>0</thr:total></entry></feed>
