Dylan Feed to Dylan Lewis's Development Blog http://www.lightspeeditsolutions.co.uk/CompanyBlogs/DylanLewis/Blog.aspx http://backend.userland.com/rss LLBLGen - Customising the DotNetTemplateEngine <h1>Introduction</h1> <p>Customers of LLBLGen Pro have access to the LLBLGen Pro SDK. This contains source code for all task performers, the TDL interpreter, the TDL parser, the LPT Parser, plugins, TypeConverters, and all command line tools and all drivers. Light Speed IT Solutions has made use of this source code and has modified the DotNetTemplateEngine with several enhancements. This article describes each modification that we have made and also the steps needed to reproduce these modifications.</p> <p>This article is based on the LLBLGen Pro - SDK version 2.6 released on the 8th of December 2008, i.e. LLBLGenProSDK_12082008.zip.</p> <p> </p> <h1>The DotNetTemplateEngine</h1> <p>A majority of the custom LLBLGen templates that we have written at Light Speed IT Solutions have been LPT templates that use the DotNetTemplateEngine template engine as the task performer. I personally am used to writing templates this way, as the LLBLGen LPT templates are very similar to CodeSmith and T4 templates, both of which I have had experience in writing before using LLBLGen. As a consequence, the ideas which I have had for extending the LLBLGen Pro SDK have focussed on what can be done with the DotNetTemplateEngine.</p> <p> </p> <h2>Using the DotNetTemplateEngine Source Code</h2> <p>The DotNetTemplateEngine class is in the file DotNetTemplateEngine.cs, in the project LptParserEngine.csproj, in the solution CodeGenerator 2.6.sln, which is included with the SDK source code. This is a Visual Studio 2005 solution. The first step in customising the SDK source code will be to upgrade the solution to a Visual Studio 2008. To support the enhancements planned, the projects in the solution will be converted to .Net version 3.5, which will require Visual Studio 2008.</p> <p>When the solution is converted and all of the projects have been converted to .Net 3.5, the next step is to fix the broken references. The readme for the LLBLGen Pro SDK recommends that the contents of the zip file in which the LLBLGen Pro SDK is distributed is copied in to the installation folder for LLBLGen Pro. This does not guarantee that the references to the LLBLGen Pro assemblies used by the source code will work. These references use paths that rely on source code not distributed with the LLBLGen Pro SDK. The following references will be broken in all projects: SD.LLBLGen.Pro.ApplicationCore, SD.LLBLGen.Pro.DBDriverCore, and SD.LLBLGen.Pro.GeneratorCore. These can be fixed by referencing the appropriate assemblies in the installation folder for LLBLGen Pro.</p> <p> </p> <h2>Deploying the Task Performer Assemblies</h2> <p>The projects in the solution also have post build event commands setup to deploy the compiled assemblies to directories used by the LLBLGen build process. These commands can be altered to deploy the assemblies to the TaskPerformers directory in your LLBLGen Pro installation directory. Assuming that the LLBLGen Pro SDK source code has been extracted in to the LLBLGen Pro installation directory, the following commands can be used:</p> <p>LptParserEngine:</p> <p> </p> <p>copy /y "$(TargetDir)\SD.LLBLGen.Pro.LptParser.*" "..\..\..\Taskperformers\"</p> <p> </p> <p>TaskPerformers:</p> <p> </p> <p>copy /y "$(TargetDir)\SD.LLBLGen.Pro.TaskPerformers.*" "..\..\..\Taskperformers\"</p> <p> </p> <p>TDLInterpreter:</p> <p> </p> <p>copy /y "$(TargetDir)\SD.LLBLGen.Pro.TDLInterpreter.*" "..\..\..\Taskperformers\"</p> <p> </p> <p>TDLParser:</p> <p> </p> <p>copy /y "$(TargetDir)\SD.LLBLGen.Pro.TDLParser.*" "..\..\..\Taskperformers\"</p> <p> </p> <h1>Upgrading to .Net 3.5</h1> <p>The DotNetTemplateEngine uses the CodeDom to compile the LPT templates. The CodeDomProvider, i.e. the CSharpCodeProvider or VBCodeProvider, is constructed without specifying a target .Net framework version. This means that a default framework version is used. This framework version is determined by a call to the static method System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() which even in a .Net 3.5 application on my computer returns C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\. Fortunately it is quite straightforward to pass a parameter to the CodeDomProvider that specifies a .Net framework version.</p> <p>The CodeDomProvider is setup in the CompileTemplates method of the DotNetTemplateEngine. A switch statement is used to construct the specific CodeDomProvider. The start of this code looks like this:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">CodeDomProvider</span><span style="font-size: 9pt; font-family: courier new;"> compiler = <span style="color: #0000ff;">null</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// now select the target compiler to use. Do this by using the templateLanguage set by the first templateID to compile. </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> templateLanguageToUse = DetermineTemplateLanguage(executingGenerator, dotNetTemplateIDs);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> logicLanguageExtension = <span style="color: #a31515;">"cs"</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">switch</span><span style="font-size: 9pt; font-family: courier new;">(templateLanguageToUse)</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;">{</span></p> <p> </p> <p>In this part of the code, the parameters for the CodeDomProvider can be setup:</p> <p> </p> <p>CodeDomProvider compiler = null;</p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">CodeDomProvider</span><span style="font-size: 9pt; font-family: courier new;"> compiler = <span style="color: #0000ff;">null</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// now select the target compiler to use. Do this by using the templateLanguage set by the first templateID to compile. </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> templateLanguageToUse = DetermineTemplateLanguage(executingGenerator, dotNetTemplateIDs);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> logicLanguageExtension = <span style="color: #a31515;">"cs"</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><o:p> </o:p> </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// Make the template engine use framework 3.5</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">Dictionary</span><span style="font-size: 9pt; font-family: courier new;">&lt;<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">string</span>&gt; providerOptions = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">Dictionary</span>&lt;<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">string</span>&gt;();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">providerOptions.Add(<span style="color: #a31515;">"CompilerVersion"</span>, <span style="color: #a31515;">"v3.5"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><o:p> </o:p> </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">switch</span><span style="font-size: 9pt; font-family: courier new;">(templateLanguageToUse)</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;">{</span></p> <p> </p> <p>The providerOptions dictionary can be then passed as a parameter to the CodeDomProvider:</p> <p>For C#:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">case</span><span style="font-size: 9pt; font-family: courier new;"> <span style="color: #a31515;">"C#"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// C# templates</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">ProduceCSCode(templateCode, referencedAssemblies, namespaces, executingGenerator, dotNetTemplateIDs);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">compiler = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">CSharpCodeProvider</span>(providerOptions);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">logicLanguageExtension = <span style="color: #a31515;">"cs"</span>;</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;">break</span><span style="font-size: 9pt; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin;">;</span></p> <p> </p> <p>For VB.NET:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">case</span><span style="font-size: 9pt; font-family: courier new;"> <span style="color: #a31515;">"VB.NET"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// VB.NET templates</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">ProduceVBNETCode(templateCode, referencedAssemblies, namespaces, executingGenerator, dotNetTemplateIDs);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">compiler = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">VBCodeProvider</span>(providerOptions);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">logicLanguageExtension = <span style="color: #a31515;">"vb"</span>;</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;">break</span><span style="font-size: 9pt; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin;">;</span></p> <p> </p> <p>All of this will change the framework version used by the LPT templates. But it is not enough to get the full benefit of .Net 3.5 in the templates. The System.Core assembly must be referenced in order to use Linq in LPT templates. Near the top of the CompileTemplates method in the DotNetTemplateEngine class, a hash table object is populated with assembly references:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">Hashtable</span><span style="font-size: 9pt; font-family: courier new;"> referencedAssemblies = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">Hashtable</span>();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #0000ff;">typeof</span>(<span style="color: #2b91af;">IBindingList</span>).Assembly.Location, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.GeneratorCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.ApplicationCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.DBDriverCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;">referencedAssemblies.Add(<span style="color: #0000ff;">this</span>.GetType().Assembly.Location, <span style="color: #0000ff;">null</span>);</span></p> <p> </p> <p>Referencing System.Core can be done by adding the path to the System.Core.dll on your computer. The location I have used is the .Net 3.5 directory within the Reference Assemblies directory in Program Files. The following code uses the ‘ProgramFiles’ environment variable to figure out the location of the Reference Assemblies directory:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">IDictionary</span><span style="font-size: 9pt; font-family: courier new;"> environmentVariables = <span style="color: #2b91af;">Environment</span>.GetEnvironmentVariables();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> framework35Directory;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">if</span><span style="font-size: 9pt; font-family: courier new;"> (environmentVariables.Contains(<span style="color: #a31515;">"ProgramFiles"</span>))</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>framework35Directory = <span style="color: #2b91af;">Path</span>.Combine((<span style="color: #0000ff;">string</span>)environmentVariables[<span style="color: #a31515;">"ProgramFiles"</span>], <span style="color: #a31515;">@"Reference Assemblies\Microsoft\Framework\v3.5"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">else</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>framework35Directory = <span style="color: #a31515;">@"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5"</span>;</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;">}</span></p> <p> </p> <p>Using this, the complete code for adding the assembly references will be:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">Hashtable</span><span style="font-size: 9pt; font-family: courier new;"> referencedAssemblies = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">Hashtable</span>();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #0000ff;">typeof</span>(<span style="color: #2b91af;">IBindingList</span>).Assembly.Location, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.GeneratorCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.ApplicationCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(<span style="color: #2b91af;">Application</span>.StartupPath, <span style="color: #a31515;">"SD.LLBLGen.Pro.DBDriverCore.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #0000ff;">this</span>.GetType().Assembly.Location, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><o:p> </o:p> </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #008000; font-family: courier new;">// Add the location of System.Core.dll to the referencedAssemblies</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #2b91af; font-family: courier new;">IDictionary</span><span style="font-size: 9pt; font-family: courier new;"> environmentVariables = <span style="color: #2b91af;">Environment</span>.GetEnvironmentVariables();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">string</span><span style="font-size: 9pt; font-family: courier new;"> framework35Directory;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">if</span><span style="font-size: 9pt; font-family: courier new;"> (environmentVariables.Contains(<span style="color: #a31515;">"ProgramFiles"</span>))</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">    framework35Directory = <span style="color: #2b91af;">Path</span>.Combine((<span style="color: #0000ff;">string</span>)environmentVariables[<span style="color: #a31515;">"ProgramFiles"</span>], <span style="color: #a31515;">@"Reference Assemblies\Microsoft\Framework\v3.5"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">else</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">    framework35Directory = <span style="color: #a31515;">@"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5"</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;">referencedAssemblies.Add(<span style="color: #2b91af;">Path</span>.Combine(framework35Directory, <span style="color: #a31515;">"System.Core.dll"</span>), <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-family: courier new;"></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-family: courier new;"></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-family: courier new;"></span></p> <p> </p> <p>Below these references is code that adds in the namespaces that are used by the template code, starting with:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.IO"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.Collections"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.Collections.Generic"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.ComponentModel"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p> </p> <p>To this, the ‘System.Linq’ namespace should be added:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.IO"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.Collections"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.Collections.Generic"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.ComponentModel"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>namespaces.Add(<span style="color: #a31515;">"System.Linq"</span>, <span style="color: #0000ff;">null</span>);</span></p> <p> </p> <p>With these changes in place, LPT templates can now use both Linq and extension methods. Extension methods are a great way for un-complicating LPT templates. In our development team we have a class library which our templates reference that provides many extension methods for existing LLBLGen objects. These are two examples of these methods:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> Returns an entity name in camel case format, e.g. UserRole =&gt; userRole;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="entity"&gt;&lt;/param&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> CamelCaseName(<span style="color: #0000ff;">this</span> <span style="color: #2b91af;">EntityDefinition</span> entity)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #0000ff;">return</span> entity.Name.Substring(0, 1).ToLower() + entity.Name.Substring(1);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><o:p> </o:p> </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> Returns an entity name with spaces to separate all capitalised parts of the name, e.g. UserRole =&gt; User Role;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="entity"&gt;&lt;/param&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> SpacedName(<span style="color: #0000ff;">this</span> <span style="color: #2b91af;">EntityDefinition</span> entity)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">    </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #0000ff;">string</span> name = entity.Name;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #2b91af;">StringBuilder</span> spacedName = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">StringBuilder</span>();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; name.Length; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #0000ff;">if</span> (i &gt; 0 &amp;&amp; i &lt; name.Length - 1 &amp;&amp; name.Substring(i, 1).ToUpper() == name.Substring(i, 1))</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>spacedName.Append(<span style="color: #a31515;">" "</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>spacedName.Append(name[i]);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #0000ff;">return</span> spacedName.ToString();</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-spacerun: yes;">    </span>}</span></p> <p> </p> <p>This is an example of using the CamelCaseName extension method with an entity and a field: </p> <p> </p> <p><span style="font-size: 9pt; background: yellow; color: #000000; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: courier new; mso-fareast-language: en-us; mso-highlight: yellow; mso-bidi-language: ar-sa; mso-ansi-language: en-gb;">&lt;%=</span><span style="font-size: 9pt; color: #000000; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: courier new; mso-bidi-language: ar-sa;"> entity.Name <span style="background: yellow; mso-highlight: yellow;">%&gt;</span>Entity <span style="background: yellow; mso-highlight: yellow;">&lt;%=</span> entity.CamelCaseName() <span style="background: yellow; mso-highlight: yellow;">%&gt;</span> = <span style="background: yellow; mso-highlight: yellow;">&lt;%=</span> entity.Name <span style="background: yellow; mso-highlight: yellow;">%&gt;</span>.Get(<span style="background: yellow; mso-highlight: yellow;">&lt;%=</span> primaryKey.CamelCaseName() <span style="background: yellow; mso-highlight: yellow;">%&gt;</span>);</span></p> <p><span style="color: #000000; font-family: courier new;"></span></p> <h1></h1> <h1>Adding a Filter Task Parameter</h1> <p>Another improvement that we have made to the DotNetTemplateEngine is to add support for a new task parameter. This task parameter is a predicate expression used to filter which objects have code generated for them, when using an emit type that specifies a type of LLBLGen object. For example, when generating code for entities, it can be used to generate code only for entities that have a primary key using an expression ‘PrimaryKeyFields.Count &gt; 0’. These expressions must resolve in to a Boolean value. The example expression is equivalent to the following lambda expression using ‘e’ as a parameter name for an entity:</p> <p> </p> <p>e =&gt; e.PrimaryKeyFields.Count &gt; 0</p> <p> </p> <h2>Linq Dynamic Expression API</h2> <p>To parse and apply this expression, the Linq Dynamic Expression API is used. This Dynamic Expression API is actually one of the C# samples distributed with Visual Studio 2008. If you have not already looked at these samples, they are contained in a zip file in the location &lt;Program Files&gt;\Microsoft Visual Studio 9.0\Samples\1033\CSharpSamples.zip. Once extracted, the Dynamic Expression API can be found in the directory LinqSamples\DynamicQuery.</p> <p>The LptParserEngine project needs to reference the DynamicQuery project. If you have not already changed the LptParserEngine project target framework to version 3.5, adding a reference to this project in Visual Studio will prompt you to change the framework version to match the DynamicQuery project version. The DynamicQuery sample includes two C# files, Dynamic.cs, and Program.cs. Only Dynamic.cs is needed, so if Program.cs produces build errors, delete it. Changing the output type of the project from Console Application to Class Library would also be advisable. The output of the Dynamic Expression API also needs to be copied to the LLBLGen Pro task performers directory. This can be done by adding a command line instruction to the post build event of the DynamicQuery project of:</p> <p> </p> <p>copy /y "$(TargetDir)\Dynamic.*" "..\..\..\Taskperformers\"</p> <p> </p> <p>This command line assumes that the DynamicQuery project directory has been copied in to CodeGenerator solution folder, so it is side by side with the other projects in the solution.</p> <p>The Dynamic.cs file contains a class called DynamicQueryable which contains extra Linq extension methods that accept text parameters instead of expression trees as parameters. It is the text based equivalent of the Queryable class in the System.Linq namespace in the System.Core assembly, but it does not support all of the Linq extension methods. For example ‘Join’, ‘GroupJoin’, and ‘SelectMany’ do not have a DynamicQueryable equivalent. In order to parse and apply the predicate expression, the DynamicQueryable equivalent of ‘Where’ will be used.</p> <p>To get the DotNetTemplateEngine class ready to use Linq, two using statements should be added:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;">using</span><span style="font-size: 9pt; font-family: courier new;"> System.Linq;</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;">using</span><span style="font-size: 9pt; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin;"> System.Linq.Dynamic;</span></p> <p> </p> <p>The second using statement brings in scope the DynamicQueryable class and makes its extension methods accessible.</p> <p> </p> <h2>Implementing the Filter Parameter</h2> <p>The first step in implementing the filter parameter is to define the string used for identifying this parameter. A string constant added to the top of the DynamicQueryable class can be used for this:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;">///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;summary&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;">///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> Name of the filter expression task parameter</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;">///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;/summary&gt;</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;">private</span><span style="font-size: 9pt; line-height: 115%; font-family: courier new; mso-fareast-theme-font: minor-latin;"> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">string</span> FilterParameterName = <span style="color: #a31515;">"filter"</span>;</span></p> <p> </p> <p>A generic method can be used to return a filtered collection of objects to generate code for:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;summary&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> Gets a filtered collecion of objects to emit code for.</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;/summary&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;typeparam name="T"&gt;</span><span style="font-size: 9pt; color: #008000; font-family: courier new;">The type of the object to filter</span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;/typeparam&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;param name="items"&gt;</span><span style="font-size: 9pt; color: #008000; font-family: courier new;">A collection of items to filter</span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;/param&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #808080; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>///</span><span style="font-size: 9pt; color: #008000; font-family: courier new;"> </span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;param name="parameters"&gt;</span><span style="font-size: 9pt; color: #008000; font-family: courier new;">The task parameters</span><span style="font-size: 9pt; color: #808080; font-family: courier new;">&lt;/param&gt;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #808080;">///</span><span style="color: #008000;"> A filtered list of objects to emit code for, if the filter task parameter is present,</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #808080;">///</span><span style="color: #008000;"> otherwise a list of all objects</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/returns&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #2b91af;">List</span>&lt;T&gt; GetFilteredEmit&lt;T&gt;(<span style="color: #2b91af;">IEnumerable</span> items, <span style="color: #2b91af;">Dictionary</span>&lt;<span style="color: #0000ff;">string</span>, <span style="color: #2b91af;">TaskParameter</span>&gt; parameters)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">if</span> (parameters.ContainsKey(FilterParameterName))</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">string</span> filterLambdaExpression = parameters[FilterParameterName].Value.Trim();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">IQueryable</span>&lt;T&gt; enumerableItems = items.Cast&lt;T&gt;().AsQueryable();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">return</span> enumerableItems.Where(filterLambdaExpression, <span style="color: #0000ff;">null</span>, <span style="color: #0000ff;">null</span>).ToList();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">return</span> items.Cast&lt;T&gt;().ToList();</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>}</span></p> <p> </p> <p>The type parameter for this method is the type of object that is filtered. The method will filter the objects if the filter parameter is present, or just return a list of the original objects.</p> <p>The DotNetTemplateEngine gets the objects to emit code for in the second overload of the Perform method; it is done within a switch statement that starts like this:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #008000;">// start code emitting process. </span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">string</span> destinationFilename = <span style="color: #a31515;">""</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">switch</span>(emitTypeToPerform)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>{</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.AllEntities:</span></p> <p> </p> <p>There is a case statement for each of the emit types that can be passed as a parameter to the DotNetTemplateEngine. Each one, except for the Generic emit type, uses a ‘for’ loop to go through each object and generate code for it. This is the start of the loop for all entities:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>case</span><span style="font-size: 9pt; font-family: courier new;"> <span style="color: #2b91af;">EmitType</span>.AllEntities:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(executingGenerator.Entities.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;executingGenerator.Entities.Count;i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">EntityDefinition</span> currentEntity = (<span style="color: #2b91af;">EntityDefinition</span>)executingGenerator.Entities[i];</span></p> <p> </p> <p>Instead of using the Entities property for the ‘for’ loop, this can be changed to filter the entities before the code is generated:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.AllEntities:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">EntityDefinition</span>&gt; entitites = GetFilteredEmit&lt;<span style="color: #2b91af;">EntityDefinition</span>&gt;(executingGenerator.Entities, parameters);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(entitites.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; entitites.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">EntityDefinition</span> currentEntity = entitites[i];</span></p> <p> </p> <p>For all of the other emit types, except generic, a similar change can be made to the for loops:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.AllTypedLists:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">TypedListDefinition</span>&gt; typedLists = GetFilteredEmit&lt;<span style="color: #2b91af;">TypedListDefinition</span>&gt;(executingGenerator.TypedLists, parameters);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(typedLists.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; typedLists.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">TypedListDefinition</span> currentTypedList = typedLists[i];</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.AllTypedViews:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">TypedViewDefinition</span>&gt; typedViews = GetFilteredEmit&lt;<span style="color: #2b91af;">TypedViewDefinition</span>&gt;(executingGenerator.TypedViews, parameters);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(typedViews.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; typedViews.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">TypedViewDefinition</span> currentTypedView = typedViews[i];</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.ActionSPCalls:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">SPCallDefinition</span>&gt; actionSPCalls = GetFilteredEmit&lt;<span style="color: #2b91af;">SPCallDefinition</span>&gt;(executingGenerator.ActionProcedures, parameters);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(actionSPCalls.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; actionSPCalls.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">SPCallDefinition</span> currentSPCall = actionSPCalls[i];</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.RetrievalSPCalls:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">SPCallDefinition</span>&gt; retrievalSPCalls = GetFilteredEmit&lt;<span style="color: #2b91af;">SPCallDefinition</span>&gt;(executingGenerator.RetrievalProcedures, parameters);<span style="mso-tab-count: 3;">                 </span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(retrievalSPCalls.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; retrievalSPCalls.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">SPCallDefinition</span> currentSPCall = retrievalSPCalls[i];</span></p> <p> </p> <p>Once these changes have been made, all objects can now be filtered using this new filter parameter.</p> <p> </p> <h1>Adding an All Relations Emit Type</h1> <p>Another type of object that is available from the LLBLGen project model is the EntityRelation object. The DotNetTemplateEngine can be enhanced to support a new emit type for generating code for each relation in the database. This can be quite useful if you want to generate objects specific to each relation but will also result in a lot of classes being generated for large, complex database.</p> <p>The emit types are defined in a private enumeration nested in the DotNetTemplateEngine class: </p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>#region</span><span style="font-size: 9pt; font-family: courier new;"> Enums</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">enum</span> <span style="color: #2b91af;">EmitType</span>:<span style="color: #0000ff;">int</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllEntities,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllTypedLists,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllTypedViews,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>ActionSPCalls,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>RetrievalSPCalls,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>Generic</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>}</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;"><span style="mso-tab-count: 1;">       </span>#endregion</span></p> <p> </p> <p>A new emit type of AllRelations can be added to this enumeration:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; color: #0000ff; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>#region</span><span style="font-size: 9pt; font-family: courier new;"> Enums</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">enum</span> <span style="color: #2b91af;">EmitType</span>:<span style="color: #0000ff;">int</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllEntities,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllTypedLists,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllTypedViews,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>AllRelations,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>ActionSPCalls,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>RetrievalSPCalls,</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>Generic</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>}</span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: courier new; mso-bidi-language: ar-sa;"><span style="mso-tab-count: 1;">       </span>#endregion</span></p> <p> </p> <p>The Perform method is responsible for taking the string emit type passed as a parameter and converting it in to an enumeration:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #2b91af;">EmitType</span> emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.Generic;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">switch</span>(emitTypeSpecified)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"allEntities"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.AllEntities;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"allTypedLists"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.AllTypedLists;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"allTypedViews"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.AllTypedViews;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"actionSPCalls"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.ActionSPCalls;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"retrievalSPCalls"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.RetrievalSPCalls;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"generic"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.Generic;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">default</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #008000;">// error</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>_performResult = <span style="color: #0000ff;">false</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">return</span>;</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 1;">       </span>}</span></p> <p> </p> <p>An extra case has to be added for AllRelations:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">case</span> <span style="color: #a31515;">"allRelations"</span>:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>emitTypeToPerform = <span style="color: #2b91af;">EmitType</span>.AllRelations;</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">break</span>;</span></p> <p> </p> <p>And then in the emit code switch statement; an extra entry has to be added for emitting code for relations. The relations will be got by aggregating all of the relations belonging to the entities in the project. This entry will also use the filter parameter to filter the actual relations for which code is emitted.</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 1;">       </span><span style="color: #0000ff;">case</span> <span style="color: #2b91af;">EmitType</span>.AllRelations:</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #008000;">// Get all of the relations in one collection</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">EntityRelation</span>&gt; relations =</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>(<span style="color: #0000ff;">from</span> <span style="color: #2b91af;">EntityDefinition</span> e <span style="color: #0000ff;">in</span> executingGenerator.Entities</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="mso-spacerun: yes;"> </span><span style="color: #0000ff;">from</span> <span style="color: #2b91af;">EntityRelation</span> r <span style="color: #0000ff;">in</span> e.Relations</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="mso-spacerun: yes;"> </span><span style="color: #0000ff;">select</span> r).ToList();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>relations = GetFilteredEmit&lt;<span style="color: #2b91af;">EntityRelation</span>&gt;(relations, parameters);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>executingGenerator.SubTaskProgressInitHandler(relations.Count);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; relations.Count; i++)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #2b91af;">EntityRelation</span> currentRelation = relations[i];</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>executingGenerator.SubTaskProgressTaskStartHandler(<span style="color: #a31515;">"Generating code for relation : "</span> + currentRelation.FullDescription);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #008000;">// Create a usable name for the relation</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">string</span> relationName = GetRelationFullName(currentRelation);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>destinationFilename = <span style="color: #2b91af;">Path</span>.Combine(fullPath, CreateFilename(filenameFormat, relationName, executingGenerator.LanguageToUse.FileExtension));</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #008000;">// Add destination file to filecache</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="mso-tab-count: 1;">       </span>((<span style="color: #2b91af;">ArrayList</span>)executingGenerator.TaskCache[<span style="color: #a31515;">"destinationFilenames"</span>]).Add(destinationFilename);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><o:p> </o:p> </span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">if</span> (!TestFileCanBeOverwritten(destinationFilename, failWhenExistent))</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #008000;">// skip</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">base</span>.LogLine(<span style="color: #a31515;">"No code generated code for relation '"</span> + currentRelation.FullDescription + <span style="color: #a31515;">"' because file '"</span> + destinationFilename + <span style="color: #a31515;">" could not be overwritten."</span>, <span style="color: #a31515;">"DotNetTemplateEngine"</span>, <span style="color: #0000ff;">true</span>, <span style="color: #0000ff;">true</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">continue</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #008000;">// all clear, generate code.</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">bool</span> removeFile = <span style="color: #0000ff;">false</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">try</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>outputWriter = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">StreamWriter</span>(destinationFilename, <span style="color: #0000ff;">false</span>, _encodingToUse);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #2b91af;">ITemplateClass</span> templateObject = (<span style="color: #2b91af;">ITemplateClass</span>)compiledTemplatesAssembly.CreateInstance(templateID);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>templateObject.___RUN(executingGenerator, parameters, outputWriter, currentRelation);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">base</span>.AddNewLogNode(_task.ElementLogNode, <span style="color: #2b91af;">LogNodeType</span>.ActionDescription, <span style="color: #a31515;">"Code generated for relation '{0}' into file '{1}' successfully."</span>, currentRelation.FullDescription, destinationFilename);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">base</span>.LogLine(<span style="color: #a31515;">"Generated code for relation '"</span> + currentRelation.FullDescription + <span style="color: #a31515;">"' in file '"</span> + destinationFilename + <span style="color: #a31515;">"."</span>, <span style="color: #a31515;">"DotNetTemplateEngine"</span>, <span style="color: #0000ff;">true</span>, <span style="color: #0000ff;">true</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">catch</span> (<span style="color: #2b91af;">TemplateAbortException</span>)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #008000;">// signal that the template should be aborted. </span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>removeFile = <span style="color: #0000ff;">true</span>;</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #008000;">// don't propagate this exception upwards, as it's not meant to be used that way.</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">finally</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">  </span><span style="mso-tab-count: 4;">                         </span><span style="color: #0000ff;">if</span> (outputWriter != <span style="color: #0000ff;">null</span>)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="mso-tab-count: 2;">              </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 5;">                                  </span>outputWriter.Close();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>executingGenerator.SubTaskProgressTaskCompletedHandler();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="color: #0000ff;">if</span> (removeFile)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span><span style="mso-tab-count: 1;">       </span>((<span style="color: #2b91af;">ArrayList</span>)executingGenerator.TaskCache[<span style="color: #a31515;">"destinationFilenames"</span>]).Remove(destinationFilename);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">try</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 5;">                                  </span><span style="color: #2b91af;">File</span>.Delete(destinationFilename);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span><span style="color: #0000ff;">catch</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 5;">                                  </span><span style="color: #008000;">// swallow</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 4;">                           </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 3;">                     </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-tab-count: 2;">              </span>}</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-tab-count: 2;">              </span><span style="color: #0000ff;">break</span>;</span></p> <p> </p> <p>This switch statement relies on an extra method called GetRelationFullName. Naming relations in a manner suitable for class names is potential problem with emitting code for relations. These names can be quite large. This implementation of GetRelationFullName generates a name similar to the value returned from the FullDescriptionWithFieldNames property of the EntityRelation class:</p> <p> </p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #808080;">///</span><span style="color: #008000;"> Gets a name for the relation suitable for a type name.</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="relation"&gt;</span><span style="color: #008000;">The relation.</span><span style="color: #808080;">&lt;/param&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;</span><span style="color: #008000;">A name for the relation suitable for a type name</span><span style="color: #808080;">&lt;/returns&gt;</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> GetRelationFullName(<span style="color: #2b91af;">EntityRelation</span> relation)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">        </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #008000;">// Create a usable name for the relation</span></span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #2b91af;">StringBuilder</span> relationName = <span style="color: #0000ff;">new</span> <span style="color: #2b91af;">StringBuilder</span>();</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>relationName.Append(relation.RelationStartName);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #0000ff;">if</span> (relation.RelationType != <span style="color: #2b91af;">EntityRelationType</span>.ManyToMany)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span><span style="color: #0000ff;">foreach</span> (<span style="color: #2b91af;">EntityFieldRelation</span> fieldRelation <span style="color: #0000ff;">in</span> relation.FieldRelations)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                    </span>relationName.Append(<span style="color: #a31515;">"_"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                    </span>relationName.Append(fieldRelation.RelationStartField.FieldName);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>relationName.Append(<span style="color: #a31515;">"_"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>relationName.Append(relation.RelationEndName);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #0000ff;">if</span> (relation.RelationType != <span style="color: #2b91af;">EntityRelationType</span>.ManyToMany)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span><span style="color: #0000ff;">foreach</span> (<span style="color: #2b91af;">EntityFieldRelation</span> fieldRelation <span style="color: #0000ff;">in</span> relation.FieldRelations)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                    </span>relationName.Append(<span style="color: #a31515;">"_"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                    </span>relationName.Append(fieldRelation.RelationEndField.FieldName);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>relationName.Append(<span style="color: #a31515;">"_"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>relationName.Append(relation.RelationType.ToString(<span style="color: #a31515;">"f"</span>));</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #0000ff;">if</span> (relation.RelationsToWalk != <span style="color: #0000ff;">null</span> &amp;&amp; relation.RelationsToWalk.Count &gt; 1)</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>{</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>relationName.Append(<span style="color: #a31515;">"Via"</span>);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">                </span>relationName.Append(relation.RelationsToWalk[0].RelationEndName);</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span>}</span></p> <p style="padding-right: 1px; padding-left: 1px; padding-bottom: 1px; margin: 0px; padding-top: 1px;"><span style="font-size: 9pt; font-family: courier new;"><span style="mso-spacerun: yes;">            </span><span style="color: #0000ff;">return</span> relationName.ToString();</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: courier new;"><span style="mso-spacerun: yes;">        </span>}</span></p> <p> </p> <p>All of this will allow you to generate code files on a per relation basis and also will include the facility to filter which relations that you want to generate code for.</p> http://www.lightspeeditsolutions.co.uk/CompanyBlogs/DylanLewis/Blog/09-03-27/LLBLGen_-_Customising_the_DotNetTemplateEngine.aspx Dylan Lewis http://www.lightspeeditsolutions.co.uk/CompanyBlogs/DylanLewis/Blog/09-03-27/LLBLGen_-_Customising_the_DotNetTemplateEngine.aspx 63022a95-8eee-412d-8de0-744a56a57854 Fri, 27 Mar 2009 09:41:55 GMT LLBLGen - Automating Code Generation with Team Foundation Server <h2>Introduction</h2> <p style="text-align: justify;">At Light Speed IT Solutions we use the code generator LLBLGen to make much of our source code for our ASP.NET and SQL Server based applications. If source code can be derived from the schema of our application database, then we try to auto-generate it, and LLBLGen is our main tool for doing this with. We also use Team Foundation Server 2008 for our source control. This article describes the steps we have taken to automate the generation of source code, and is a guide as to how other development teams can automate the generation of their source code when using LLBLGen and Team Foundation Server.</p><br/> <h2>The Manual Code Generation Process</h2> <p style="text-align: justify;">Code generation with LLBLGen normally takes place outside of Visual Studio using the LLBLGen Pro application. The process of regenerating using the LLBLGen Pro application, in response to a schema change has many steps which a developer has to perform. Within the LLBLGen Pro application it is typical to do these steps after a schema change:</p> <ol> <li><span>Refresh the catalogue that you have made schema changes to</span> </li> <li><span>Add in any extra entities from tables or views that you have added to the database</span> </li> <li><span><span style="font: 7pt 'times new roman'; font-size-adjust: none; font-stretch: normal;"></span>Regenerate all code created by LLBLGen</span> </li> </ol> <p style="text-align: justify;">In our projects we use LLBLGen to create a data layer, business layer, and web user controls all derived from the database schema. We also use the Linq to SQL templates, generate unit tests and utility classes for making test data, and also generate code that makes use of the LLBLGen Authorizer system. This means that regenerating all of this code would require using the generate feature of LLBLGen Pro six times.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">In addition to using the LLBLGen Pro application, we also have to make sure that the code we are regenerating is checked out and that any new files that are created are checked in to Team Foundation Server source control once the code generation is completed. As the code generation takes place outside of Visual Studio, Visual Studio does not add the new files created by LLBLGen in to source control. While checking out the code generated files is easy, adding in all the additional files, that get created in response to the schema changes, does take a lot longer. We also want to make sure that we are using the latest version of the LLBLGen project file, which we have under source control and any custom LLBLGen code generation templates and task files we are using. We don’t want a developer to generate code using templates that are weeks out of date, or to not incorporate the latest changes to the project file. We also have a class library containing utility classes used by the LLBLGen templates. Before code generation takes place, a developer needs to get the latest version of this class library, build it, and copy it to the LLBLGen Pro directory, from where it is referenced by the templates.</p> <h2>Automating the Code Generation</h2> <p style="text-align: justify;">Performing all of these steps each time a schema change is made, and not missing any of them out has proved to be a challenge. Problems happen when even one of these steps is forgotten. Forgetting to add in a file to source control created by LLBLGen will not cause any build errors for the developer who does the code generation, but it will do for the next developer who gets the latest version of the affected projects. Build errors caused by not having the latest templates, tasks, and utility classes can be confusing for a developer who does not know what changes have been made to these since the last time the code was generated.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">Fortunately LLBLGen Pro users can obtain the LLBLGen Pro SDK which contains two command line tools which can be used to automate the code generation process. Using these in combination with the Team Foundation Server command line tools, and the MSBuild command line tool, the code generation process can be automated to the point that a single click of a button can do all of these tasks.</p> <h3>LLBLGen Pro SDK</h3> <p style="text-align: justify;">The LLBLGen Pro SDK is available to all people who have purchased LLBLGen Pro. It is distributed as a zip file that contains many different Visual Studio solutions. The two which are useful for automating the code generation process are the CommandLineGenerator and CliRefresher solutions. Both of these are solutions for building a command line tool. The CommandLineGenerator not surprisingly allows you to generate code using the command line. The actual program it compiles is called the CliGenerator. The CliRefresher allows you to refresh the catalogues in your LLBLGen project file from the command line.</p> <h3>Team Foundation Server Command Line Tools</h3> <p style="text-align: justify;">To automate the code generation process, we use two different command line tools from Team Foundation Server. The first is the main Team Foundation Server command line tool, ‘TF.exe’. The second command line tool is distributed as part of the Team Foundation Server 2008 power tools (available for free from: <a href="http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx">http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx</a>) called ‘TFPT.exe’. TF.exe can be used to perform many operations with Team Foundation Server including getting the latest version of files under source control, checking out files and checking them in. TFPT.exe has a command called ‘online’, which searches for offline changes made within a source controlled project, and notifies Team Foundation Server of these changes. It does the same job as the ‘Go Online’ button in Visual Studio, which is displayed when you work disconnected from Team Foundation Server.</p> <h2>Writing a Code Generation Batch File</h2> <p style="text-align: justify;">Using a batch file, these command line tools can be used to automate the code generation process. If you are unfamiliar with batch files, this is a good guide for learning about them: <a href="http://commandwindows.com/batch.htm">http://commandwindows.com/batch.htm</a>. We want the following steps to be automated when generating code with LLBLGen:</p> <ol> <li><span><span style="font: 7pt 'times new roman'; font-size-adjust: none; font-stretch: normal;"></span>Get the latest version of the LLBLGen project file</span> </li> <li><span>Check out the LLBLGen project file</span> </li> <li><span>Refresh the schema information in the LLBLGen project file</span> </li> <li><span>Get the latest version of any custom LLBLGen templates and task files that are used</span> </li> <li><span>Get the latest version of any class libraries referenced by LLBLGen templates</span> </li> <li><span>Build and deploy the class libraries referenced by LLBLGen templates</span> </li> <li><span>Check out the files that we are going to regenerate</span> </li> <li><span>Generate the code with LLBLGen</span> </li> <li><span>Add any new files created in to Team Foundation Server source control</span> </li> </ol> <p style="text-align: justify;">The command line tools already mentioned will be used to perform these steps. Getting the latest version of a file in source control is done with the TF.exe command. Using it in a batch file could look like this:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET TFCMD="%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\tf"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET ROOT=$/Your Team Project/Your Solution</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "%ROOT%/Your LLBLGen Project file.lgp" /version:T</span></p> <p style="text-align: justify;">In the above batch file content, two variables are declared: TFCMD and ROOT. The TFCMD variable stores the location of the TF.exe command as it will be used quite frequently. The ROOT variable stores the location in Team Foundation Server source control of the solution for which code will be generated. This is also something that will be referred to frequently and so it is stored as a variable. TF.exe is called with the parameter ‘get’ to get a file from source control, the second parameter is the file which we want to get, and the third parameter is the version. The letter ‘T’ is used to indicate that it is the latest version that we want to get.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">As we want to update the schema in the LLBLGen project file, first of all we need to check it out. This is also done with the TF.exe command and it will look like this:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout "%ROOT%/Your LLBLGen Project file.lgp"</span></p> <p>Next we want to update the schema using the CliRefresher command line tool:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliRefresher" 1 "Your LLBLGen Project file.lgp"</span></p> <p style="text-align: justify;">The CliRefresher tool is called with the first parameter of 1 to indicate that the error log is shown, and the second parameter is of course the project file. This line assumes that the tool is in the LLBLGen directory. As the tool references key LLBLGen assemblies this is a good location for it.</p> <p style="text-align: justify;">The next step is to get the latest version of any custom templates and task files that are used for the solution. At Light Speed IT Solutions we use a Team Foundation Server Team Project called LSITS as a respository for various internal libraries and content shared between projects. This Team Project also contains the class library containing the utility classes which is used by our custom LLBLGen templates. Before generating any code it is important that we have the latest version of the tasks, templates and this class library. The part of the batch file for this is:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Tasks" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Templates" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Template Debugger" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%SystemRoot%\Microsoft.NET\Framework\v3.5\msbuild "D:\Projects\LSITS\LLBLGen Template Debugger\TemplateUtils\TemplateUtils.csproj"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">if %ERRORLEVEL% == 0 GOTO End</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">echo Build Failure - Are you running LLBLGen?</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">pause</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">:End</span></p> <p style="text-align: justify;">TF.exe is used again to get the latest version of the files we need, this time using an extra parameter /recursive to make sure that all files under the specified source control folder are retrieved. The msbuild command line tool is called to build the TemplateUtils class library project, which has an extra MSBuild task that copies the assembly in to the LLBLGen directory. This is the task and target used:</p> <p style="margin-bottom: 0pt; line-height: normal;"><span style="font-size: 9pt; color: #0000ff; font-family: consolas;">&lt;</span><span style="font-size: 9pt; color: #a31515; font-family: consolas;">Target</span> <span style="font-size: 9pt; color: #ff0000; font-family: consolas;">Name</span><span style="font-size: 9pt; color: #0000ff; font-family: consolas;">=</span><span style="font-size: 9pt; font-family: consolas;">"<span style="color: #0000ff;">AfterBuild</span>"<span style="color: #0000ff;">&gt;</span></span></p> <p style="margin-bottom: 0pt; line-height: normal;"><span style="font-size: 9pt; color: #0000ff; font-family: consolas;">&lt;</span><span style="font-size: 9pt; color: #a31515; font-family: consolas;">Copy</span> <span style="font-size: 9pt; color: #ff0000; font-family: consolas;">SourceFiles</span><span style="font-size: 9pt; color: #0000ff; font-family: consolas;">=</span><span style="font-size: 9pt; font-family: consolas;">"<span style="color: #0000ff;">@(MainAssembly)</span>" <span style="color: #ff0000;">DestinationFolder</span><span style="color: #0000ff;">=</span>"<span style="color: #0000ff;">C:\Program Files\Solutions Design\LLBLGen Pro v2.6\</span>"<span style="color: #0000ff;"> /&gt;</span></span></p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: consolas;">&lt;/</span><span style="font-size: 9pt; color: #a31515; line-height: 115%; font-family: consolas;">Target</span><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: consolas;">&gt;</span></p> <p style="text-align: justify;">This step is done by the project file, not the batch file as we want this assembly to be copied in to the LLBLGen directory every time it is built, not just when it is built by this batch file.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">After the assembly is compiled the %ERRORLEVEL% variable is checked to see if the return value from the msbuild command is 0, which means that everything was OK with compiling the project. If it was not 0 then a message is displayed and the batch file is paused. A common cause of the compilation failing is if a developer running the batch file also has the LLBLGen Pro application running, this assembly cannot be copied in to the LLBLGen directory. As soon as you generate code with LLBLGen Pro is loads any assemblies used by the code generation templates in to its app domain. This then prevents the files from being overwritten and cause the copying of the TemplateUtils assembly in to the LLBLGen directory to fail.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">Next the files that will be regenerated have to be checked out. Which files depends entirely on what is being generated by LLBLGen. In the example below, it will be assumed that there are templates that generate code for a data layer, business layer, unit tests, and web application project, all of which are located in immediate subdirectories of the solution.</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/DataLayer"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/BusinessLayer"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/UnitTests"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/Web"</span></p> <p style="text-align: justify;">These commands can be a specific as necessary only checking out directories that contain auto-generated code, but to make this example simple, all of the projects are being checked out.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">After all of this preparation, the CliGenerator tool can be called to do the actual code generation. This is an example of one of the calls to CliGenerator:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliGenerator" "Your LLBLGen Project file.lgp" YourProject.DataLayer C# ".NET 3.5" Adapter SD.Presets.Adapter.General2008 DataLayer 0</span></p> <p style="text-align: justify;">There are several parameters that will vary depending on what code generation you actually will be doing. The project file is the first parameter. Immediately after is the root namespace that the code will be using. In the above example, ‘YourProject.DataLayer’ is used as the root namespace. Following this is the target language to use, in this case C#, followed by the target platform, .Net 3.5. After these are the template group and the preset name. Specifying the template bindings is not required by the CliGenerator as the template bindings will be inferred from the other parameters. The last two parameters are the target directory and whether to output to a log file (0 meaning don’t write to a log file). In this example, ‘DataLayer’ is a directory immediately under the solution folder where the data layer projects are kept. The paths you need to provide can be paths relative to the location of the batch file, in this case it is assumed to be in the root of the Visual Studio solution. </p> <div style="text-align: justify;"></div> <p style="text-align: justify;">The CliGenerator should be called as many times as needed to generate all of the auto-generated code. After this, new files that have been created can be added in automatically to source control using the TFPT.exe command. Using the data layer again as an example, this statement can be used to add in the new files:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET TFPTCMD="%ProgramFiles%\Microsoft Team Foundation Server 2008 Power Tools\tfpt"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt DataLayer\*.cs /recursive</span></p> <p style="text-align: justify;"><span>The /nopromt parameter tells the </span>TFPT.exe command to pend the changes found automatically. Without it the TFPT.exe command displays a dialogue window with all of the changes it has found, just like the ‘Go Online’ button in Visual Studio. The <span>/adds parame</span>ter tells the command to automatically add new files found. In the above example DataLayer\*.cs is used as the path of the items to check. In this case we are interested in finding new classes created by LLBLGen, so we are only interested in checking for new C# files. The *.cs part of the path describes a filter for the files checked.</p> <p>Adding the files is the final step, so now a complete batch file can be assembled:</p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET TFCMD="%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\tf"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET ROOT=$/Your Team Project/Your Solution</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "%ROOT%/Your LLBLGen Project file.lgp" /version:T</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout "%ROOT%/Your LLBLGen Project file.lgp"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliRefresher" 1 "Your LLBLGen Project file.lgp"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Tasks" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Templates" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% get "$/LSITS/LLBLGen Template Debugger" /version:T /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%SystemRoot%\Microsoft.NET\Framework\v3.5\msbuild "D:\Projects\LSITS\LLBLGen Template Debugger\TemplateUtils\TemplateUtils.csproj"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">if %ERRORLEVEL% == 0 GOTO End</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">echo Build Failure - Are you running LLBLGen?</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">pause</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">:End</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/DataLayer”</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/BusinessLayer”</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/UnitTests”</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFCMD% checkout /recursive "%ROOT%/Web”</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliGenerator" "Your LLBLGen Project file.lgp" YourProject.DataLayer C# ".NET 3.5" Adapter SD.Presets.Adapter.General2008 DataLayer 0</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliGenerator" "Your LLBLGen Project file.lgp" YourProject.BusinessLayer C# ".NET 3.5" Adapter BusinessLayer.Presets BusinessLayer 0</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliGenerator" "Your LLBLGen Project file.lgp" YourProject.UnitTests C# ".NET 3.5" Adapter UnitTests.Presets UnitTests 0</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"%ProgramFiles%\Solutions Design\LLBLGen Pro v2.6\CliGenerator" "Your LLBLGen Project file.lgp" YourProject.Web C# ".NET 3.5" Adapter Web.Presets UnitTests 0</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">SET TFPTCMD="%ProgramFiles%\Microsoft Team Foundation Server 2008 Power Tools\tfpt"</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt DataLayer\*.cs /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt BusinessLayer\*.cs /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt UnitTests\*.cs /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt Web\*.cs /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt Web\*.aspx /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">%TFPTCMD% online /adds /noprompt Web\*.ascx /recursive</span></p> <p><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">pause</span> </p> <p>In the web project, any new .aspx and .ascx files are also added in addition to new C# files. </p> <h1>One Click Code Generation</h1> <p style="text-align: justify;">The batch file on its own can be used for regenerating all of the source code quite conveniently but Visual Studio can be configured to make the process better. By default, Team Foundation Server source control does not get the latest version of a file when it is checked out, but it can be configured to do so. When using Team Foundation Server source control, and generating code with LLBLGen, if many people in the project team are generating source code, this can lead to conflicts when checking the generated code in. If a developer generating the source code did not have the latest version of the files before checking them back in, the developer will be asked to resolve conflicts with all of the files. Team Foundation Server usually can resolve the conflicts automatically but with hundreds or more files this can take a while. If the option to get the latest version of a file when checked out is switched on, situations like this will be less frequent. This option can be found in the Tools-&gt;Options... menu item:</p> <p style="text-align: justify;"> </p> <p><span><img alt="" style="border: 0px solid;" src="http://www.lightspeeditsolutions.co.uk/Images/Blogs/image001.jpg" v:shapes="Picture_x0020_16" /></span></p> <p> </p> <p style="text-align: justify;">Getting the latest version of a file being generated also helps deal with another potential problem: having user code regions discarded. If the files being generated are up to date before the code generation takes place, then they will contain any user code regions added by other developers.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">Another change to Visual Studio that can be made to improve the process is to make the batch file for generating the source code an external tool. The external tools used by Visual Studio can be found by using the Tools -&gt; Externals Tools... menu item:</p> <p> </p> <p><span></span><span><img alt="" style="border: 0px solid;" src="/Images/Blogs/image002.jpg" v:shapes="Picture_x0020_4" /></span></p> <p> </p> <p><span></span></p> <p>This is the Externals Tools dialogue window with a batch file as an additional external tool:</p> <p> </p> <p><span><img alt="" style="border: 0px solid;" src="/Images/Blogs/image003.jpg" v:shapes="Picture_x0020_7" /></span></p> <p> </p> <p><span></span></p> <p style="text-align: justify;">The batch file has been configured to use the solution directory as the working directory. This is the normal location for the batch file. It also has been configured to use an Output window. This has the advantage that all output from the batch file is contained within the Output window. This makes it easier to track down errors, as a normal command window that the batch file runs in has a limited buffer for the text it outputs. It does have the disadvantage that any pause statements in your batch file will be ignored.</p> <div style="text-align: justify;"></div> <p style="text-align: justify;">This tool can be added as an item to a toolbar within Visual Studio. It may be tempting to make a new toolbar for all of your code generation batch files but in my experience new toolbars tend to disappear the next time Visual Studio is loaded. The best thing to do is to add the external tool to an existing toolbar. This can be done by dragging the external tool on to a toolbar from the ‘Customize’ dialogue window (from Tools -&gt; Customize):</p> <p> </p> <p><span><img alt="" style="border: 0px solid;" src="http://www.lightspeeditsolutions.co.uk/Images/Blogs/image004.jpg" v:shapes="_x0000_i1025" /></span></p> <p> </p> <p>As the list of external commands is not named properly, i.e. they are just External Command 1, External Command 2 and so on; the external tool you added will be numbered by the position in the list of external tools in the Externals Tools dialogue window. As the GenerateAll batch file was the sixth external tool it is now ‘External Command 6’. Once the command is on a toolbar, it will be displayed with the original name you gave it when you added it as an external tool. And also, once it is on the toolbar, it can be run by clicking on it within Visual Studio. </p> <h1>Configuring the Catalogue Refreshing</h1> <p style="text-align: justify;">By default new tables and views are not added as entities when they are detected during a refresh of a catalogue. In order to automate the code generation process further, LLBLGen can be configured to do this, allowing the CliRefresher tool to add new entities automatically. The CliRefresher tool seems to ignore the settings within an LLBLGen project file for the catalogue refresher, but it will use the preferences setup within a developer’s user profile. For LLBLGen 2.6, there is an XML preferences file stored within the user profile application data directory, i.e. C:\Documents and Settings\&lt;Your User Name&gt;\Application Data\LLBLGen Pro. In this directory are several files used by LLBLGen, the preferences are stored in the Preferences26.xml file. In this file is an XML element for the setting ‘AddNewElementsAfterRefresh’:</p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: &quot;courier new&quot;;">&lt;</span><span style="font-size: 9pt; color: #a31515; line-height: 115%; font-family: &quot;courier new&quot;;">addNewElementsAfterRefresh</span> <span style="font-size: 9pt; color: #ff0000; line-height: 115%; font-family: &quot;courier new&quot;;">value</span><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: &quot;courier new&quot;;">=</span><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"<span style="color: #0000ff;">true</span>"<span style="color: #0000ff;"> /&gt;</span></span></p> <p style="text-align: justify;">This is false by default but when set to true, tables will be added as entities automatically, as well as typed views and stored procedures. If you want views added automatically as entities then this setting can also be set to true:</p> <p><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: &quot;courier new&quot;;">&lt;</span><span style="font-size: 9pt; color: #a31515; line-height: 115%; font-family: &quot;courier new&quot;;">addNewViewsAsEntitiesAfterRefresh</span> <span style="font-size: 9pt; color: #ff0000; line-height: 115%; font-family: &quot;courier new&quot;;">value</span><span style="font-size: 9pt; color: #0000ff; line-height: 115%; font-family: &quot;courier new&quot;;">=</span><span style="font-size: 9pt; line-height: 115%; font-family: &quot;courier new&quot;;">"<span style="color: #0000ff;">true</span>"<span style="color: #0000ff;"> /&gt;</span></span></p> <p> </p> <br /> http://www.lightspeeditsolutions.co.uk/CompanyBlogs/DylanLewis/Blog/09-03-04/LLBLGen_-_Automating_Code_Generation_with_Team_Foundation_Server.aspx Dylan Lewis http://www.lightspeeditsolutions.co.uk/CompanyBlogs/DylanLewis/Blog/09-03-04/LLBLGen_-_Automating_Code_Generation_with_Team_Foundation_Server.aspx 51bbc4bb-b5f8-4308-9958-216ee3ae698e Wed, 04 Mar 2009 15:00:10 GMT