Archive

Archive for the ‘Templates’ Category

CodeFluent Entities and the Localization Aspect: how to show localizable properties in the design surface

April 12, 2013 Leave a comment

Using CodeFluent Entities, you can use “Member Format Expressions” (a.k.a “MFEX”) to customize the way names of entities and properties are formatted. We already have blogged about that feature here:

http://blog.codefluententities.com/2012/01/12/codefluent-entities-member-format-expressions-part-1/

http://blog.codefluententities.com/2012/01/13/member-format-expressions-part-2/

In this post, we’re going to explain how to create an MFEX that will display this on the surface when selected:

As you clearly see, I have defined two localized properties on my model (on the Name property of the Campaign entity, and on the Name property of the Space entity). But wait! A red ‘Localizable’ text is appended to the right of the property name. How do I do this?

Let start with this expression, demonstrated in the previous blog post:

<font condition=IsKey color=’red’>{#Name}<else/><font color=’blue’>{#Name}</font></font>

With this expression, key properties will be shown in red and other properties will be shown in blue. The condition syntax is in fact a .NET expression. IsKey is a property (of Boolean type) of the CodeFluent.Model.Property class. If I was writing C# code, I could do this ‘if (myProperty.IsKey)’ etc… But MFEX conditions also support “dot navigation”, so you could write this:

<font condition=Rules.Count color=’red’>{#Name}<else/><font color=’blue’>{#Name}</font></font>

In this case, we are navigating on the Rules property of the CodeFluent.Model.Property class, and on the Count property of the CodeFluent.Model.RuleCollection class. Count is of type Int32 and the condition evaluator needs a Boolean, so it just tests the resulting Int32 against 0, so the condition is equivalent to “Rules.Count > 0″. So this expression will show in red all the properties that have CodeFluent Entities rules defined on it.

Well, it turns out MFEX also supports (partially) methods in conditions. So, here is how to display localized properties:

{Name} <font color="red" condition="'true'=Element.GetAttribute('localizable','http://www.softfluent.com/codefluent/patterns/localization/2008/1')">Localizable</font>

Note : it’s important to respect the difference between the single quote and the double quote characters here.

So, the condition is an expression with an operation. = is the ‘equality insensitive’ operator. It means it uses equality but is case insensitive in the case of string comparison. Here is the list of available operators:

  • == or = : Equal
  • != or <> : NotEqual
  • [=CS] : EqualCaseSensitive
  • [!=CS] : NotEqualCaseSensitive
  • >= : GreaterThanEqual
  • <= : LesserThanEqual
  • > : GreaterThan
  • < : LesserThan
  • [StartsWith] : StartsWith
  • [StartsWithCS] StartsWithCaseSensitive
  • [EndsWith] : EndsWith
  • [EndsWithCS] : EndsWithCaseSensitive
  • [Contains] : Contains
  • [ContainsCS] : ContainsCaseSensitive

The condition will compare the literal string ‘true’ with the result of a method call that starts on the Element property of the CodeFluent.Model.Property class, which is of System.Xml.XmlElement type. XmlElement has a method called GetAttribute that simply gets an XML attribute given it’s local name (without a prefix if it’s in a specific XML namespace) and the XML namespace.

So, with this condition, we are accessing the XML element underlying the CodeFluent Entities Property concept. When a property is marked as localized, the corresponding XML text (in memory) is just modified like this:

  <Campaign namespace="SoftFluent.Advertising1" >
    <Id />
    <Name _loc:localizable="true" />
  </Campaign>

Happy MFEXing!

The CodeFluent R&D Team.

Generate ASP .NET Web API Controllers using Templates

March 20, 2013 Leave a comment

 

In a precedent post we have shown how to build an ASP .NET WebAPI Controller to access the generated Business Object Model (BOM).
 
We saw how to implement manually a Web API Controller for one entity of our model.
 
Now, we are going to see how to build a Template in order to automatically generate a Web API Controller for each one of the entities in our model.
 
We are going to use the “CarRental” demo project included with CodeFluent Entities. It was the same sample project that we used when we created the Web API Controller.
 
The first thing we have to do is create our template file.

 

Templates location

Templates location

 

Our template must be prefixed by “[Template]” and have an extension of type “.tpl”.

 
Before writing our template let’s create a producer for our template.
 

Template Producer

Template Producer


 
The “Source Directory” is the location of our template folder and the “Target Directory” is where our files will be generated, in my case I have a folder called “ApiControllers” in my MVC 4 Web Application project.
 
At the bottom of our template we fix some parameters.

[%@ template
enumerable="Producer.Project.Entities"
enumerableItemName="entity"
enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), entity.Name) + "Controller.cs"' %]

 
That means that we are going to iterate through all the entities in our project (Producer.Project.Entities). Inside the template we can access the current enumerated entity by the name “entity”. And the name of the generated file (for each entity) will be “[EntityName]Controller.cs”.
 
Now we can write the content of our Api Controller. Let’s start by creating only the Controller class.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the Template Producer.
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace [%=entity.Namespace%].Web.ApiControllers
{
	using System.Collections.Generic;
	using System;
	using System.Net;
	using System.Net.Http;
	using System.Web.Http;

    public class [%=entity.Name%]Controller : ApiController
    {
    }
}

 
If we build our CodeFluent Entities project we must see our Api Controllers appear.
 

Generated API Controllers

Generated API Controllers


 
Now let’s implement the Api Controller methods. We will use almost the same implementation as we did in the post “Using ASP .NET Web API with CodeFluent Entities”.

// GET api/[%=entity.Name%]
public IEnumerable<[%=entity.Name%]> Get()
{
    return [%=entity.SetFullTypeName%].LoadAll();
}

// POST api/[%=entity.Name%]
public HttpResponseMessage Post([FromBody][%=entity.Name%] value)
{
	if(value == null || !value.Save())
	{
		return Request.CreateResponse(HttpStatusCode.BadRequest);
	}
	return Request.CreateResponse(HttpStatusCode.OK, value);
}

// PUT api/[%=entity.Name%]
public HttpResponseMessage Put([FromBody][%=entity.Name%] value)
{
	if(value == null || !value.Save())
	{
		return Request.CreateResponse(HttpStatusCode.BadRequest);
	}
	return Request.CreateResponse(HttpStatusCode.OK, value);
}

 

For the Delete and Get (for a single element) methods we need to do some work to manage the entity keys. Indeed, it is possible that some entities have multiple keys.

// DELETE api/[%=entity.Name%]/*ids
public HttpResponseMessage Delete(string ids)
{
	ids = ids.Replace('/', '|');
    [%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
	if(value != null && value.Delete())
	{
		return Request.CreateResponse(HttpStatusCode.NoContent);
	}
	return Request.CreateResponse(HttpStatusCode.NotFound);
}

	// GET api/[%=entity.Name%]/*ids
public [%=entity.Name%] Get(string ids)
{
	ids = ids.Replace('/', '|');
    [%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
	if(value == null)
	{
		throw new HttpResponseException(HttpStatusCode.NotFound);
	}
	return value;
}

 
We use a feature in MVC (and Web API) routes that allows us to handle a variable number of segments in a URL pattern.
 
So we will need to make some changes in our routing configuration. I have registered my routes for the Web API in a separate file called “WebApiConfig” (cf. Using ASP .NET Web API with CodeFluent Entities). The trick lies in the “*” before the parameter name (*ids).

config.Routes.MapHttpRoute(
                           name: "DefaultApi",
                           routeTemplate: "api/{controller}/{*ids}",
                           defaults: new { ids = RouteParameter.Optional }
                          );

 

For example, in order to retrieve a specific instance of the entity “InventoryDetail” we need three keys, so the URL to get an instance of “InventoryDetail” will be: http://server/api/InventroyDetail/1/2/3.

 
If we build our CodeFluent Entities project and take a look at the inside of a Controller we will see the complete implementation.
 
Now we only have to test our Controllers. We can use the same tests that we have done in the precedent post related to the ASP .NET Web API.

 
Regards.
 
Pablo Fernandez Duran

Website Templates and Custom Renderers

December 4, 2012 Leave a comment

There are basically two ways to customize web sites generated by CodeFluent Entities:

1) edit the generated files in place. The generated code is very readable, and by design easy to customize.
2) modify how the out-of-the-box site is generated. Please note these auto-generated sites are very well suited for back-end/back-office/administration/testing/sample purpose. However, they are generated using site templates, and these templates can be customized. We will try to explain how.

Site templates are located in \Program Files (x86)\SoftFluent\CodeFluent\Modeler\Templates\UI. Here you will find the various templates for ASP.NET, MVC, Ajax, etc…

These templates are a good start to build your own. Each template is composed of two directories:

    • A directory that contains a cf_template.xml which is the template manifest, used by tools such as Visual Studio. Let’s say it’s named ‘MyAspNet’ for our example.
    • Another directory named [directoryName]_Renderers. So it should be named MyAspNet_Renderers for our example.

Both directories can contain template files (text files with the .tpl extension) or any other files. Template files are files that are executable files and can run in the context of the model being produced (more here:http://www.softfluent.co…_TheTemplateEngine.html and here: http://www.softfluent.co…s_TemplateProducer.html).

The first directory will define the target site files. The renderers directory will contains the renderers implementation. Now the question: what is a renderer?

A renderer in a CodeFluent Entities model is an abstract platform-independent item which basically has two important properties: a name, and a type (unspecified, read, write, create, column, parameter), and will be used to define how a concept will be rendered ultimately on a specific platform (whatever that platform will be: web, winforms, WPF, etc.).
Renderers can be associated with properties, view properties, entities or method parameters. Renderers can be shared.

For example, let’s suppose you handle a lot of IP Address in your application. There’s nothing built-in in the product but many entities have properties that are of the IP Address type. Then, you would declare a renderer named ‘IPAddress’ (for example) and associate this renderer to all the properties of that type.
At production time, a producer such as the ASP.NET producer will relate the renderer definition to a concrete UI artifact using it’s name and type. In the case of the ASP.NET producer, a renderer will be simply represented by a file, containing some HTML (or ASP.NET) fragment. You can see what the out-of-the-box renderers look like if you open the files in the [directory]_Renderers directory of the out-of-the-box templates. A renderer file name starts with “Renderer.”.

Let’s go to CodeFluent Entities installation directory, and navigate through the Templates\UI directory. Here you can see a set of folders containing the templates and renderer.

We’re going to create a new template from an existing one and also add a renderer. To do so copy the following folders to a folder called “UI” in the location of your choice (Note the folder root must contain ‘UI’):

  • AspNet
  • AspNet_Renderers
  • AspNetWebForms
  • AspNetWebForms_Renderers

Rename the last two copied folders like this:

  • CustomWebsite
  • CustomWebsite_Renderers
    You should have something like this:

image

We We copied two website templates because the AspNetWebForms template inherits the AspNet template.

You can already customize your website here. For instance edit CustomWebsite\Default.aspx.tpl, and modify the page title by modifying the
<%@ Page %> tag with something like this:

<%@ Page Title=”This is my Custom Website Home Page” …

Now add a new file called Renderer.MyContactSource.tpl in the CustomWebsite_Renderers folder. Open this file in a text editor such as NotePad and type the following text: “this is my custom Contact Source”. It is an unspecified renderer because the file name does not end with Write, or Column for example.

image

Now start Visual Studio, and create a CodeFluent Entities project (Demo.ContactManager, C#, SQL Server, ASP.NET WebForms). Go in the Contact Entity, select the ContactSource property and add a ‘MyContactSource’ renderer of unspecified type:

Now, double-click on the ASP.NET Webforms producer, and configure it to point to your custom site template:

Build the project, and execute the generated web site. You should now see this when you try to Add or Edit a new Contact:

what happened is, at generation time, every time a property is associated with the MyContactSource renderer, it will be rendered using the content of the Renderer.MyContactSource.tpl file. This file just contain a pure (HTML) text, but it could contain anything you would like, including server-side ASP.NET controls. This file can also contain template code so you can indeed have it vary using the model and the source object it was instantiated from at generation time.
For example, if you don’t like the drop down list that’s used to represent relations by default, you can just modify the Renderer.Relation.Write.tpl content and this will change how relations are rendered (in write mode) in every screen of the application, because Relation is the name of the default renderer associated with M:0/1 or 0/1:M relations. Association is the name of the default renderer associated with M:N relations.

Besides, navigate back to the homepage and note that Tab’s title reflects our change made in the Default.aspx file.

Therefore, thanks to Renderers and custom templates you can generate full customized websites.

Cheers

Using the SQL Server Template Producer to generate Clustered Indexes

November 27, 2012 Leave a comment

In this post we’ll see how using CodeFluent Entities’ SQL Server Template Producer, you can generate SQL scripts using  the built-in template engine whilst accessing the inferred meta-model, and then automatically deploy the generated script on your desired server.

By default SQL Azure and SQL Server add the clustered index on the primary key if a clustered index on the table does not already exist and if you do not specify a unique nonclustered index. In the case where the primary key is of GUID type it won’t be efficient. The reason for this is that GUIDs are generated in non-sequential order and SQL Server orders a clustered index sequentially. It will work – SQL Server will let you build a clustered index around a unique identifier column, however it will cause the SQL Server to do unnecessary work and cause performance slowdowns.

That being said, what we can do is using the SQL Template Producer to remove all inefficient clustered indexes and recreate them on the right columns. Let’s even go a bit further and create a little aspect that will add a property on each property to tell if a clustered index needs to be created or not on that particular property.

Add a new Part called IsClusteredIndexAspect and past it the following code (replacing the defaultNamespace’s value by yours):

<cf:project xmlns:cf=”http://www.softfluent.com/codefluent/2005/1” defaultNamespace=”yourNamespace”>

<cf:pattern name=”IsClusteredIndex Aspect” namespaceUri=”http://www.sample.com/aspects/isclusteredindexaspect/2012/11” preferredPrefix=”sa” step=”Tables”>

<cf:message class=”_doc”>
This aspect creates an extra IsClusteredIndex bool property on every property.
</cf:message>

<cf:descriptor name=”IsClusteredIndex” typeName=”boolean” targets=”Property” defaultValue=”false” displayName=”IsClusteredIndex” description=”Should the IsClusteredIndex Aspect apply to this property?” />

</cf:pattern>
</cf:project>

This will create our aspect and add a IsClusteredIndex property on each property in the “Aspects and Producers” property grid:

image

You can by now choose which property you want to use as a clustered index. Obviously this property should be set to true only on one property by entity since clustered index cannot be applied on several columns.

Now let’s write a script that will remove all clustered indexes and then create new ones based on the columns selected thanks to our aspect. In a file called “[Template]CreateIndexes.sql” add it the following code (Note that this code is only an illustration for this post, it does not take into account constraints, primary keys and so on):

[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Persistence"%]
[%@ namespace name="CodeFluent.Producers.SqlServer"%]
/* [%=Producer.GetSignature()%] */

[%foreach (Entity e in Producer.Project.Entities)
{%]
    --remove any existing clustered index on e.Table.FullName
    --[...]
  
   [%foreach (Property p in e.Properties)
    {
        if (p.GetAttributeValue("sa:IsClusteredIndex", false))
        {%]      
        --create your index such as:
        CREATE CLUSTERED INDEX [CL_[%=p.Entity.Table.Name%]] ON [%=p.Entity.Table.FullName%] ([[%=p.Column.Name%]]);
        GO
        [%}
    }
}%]

 

Create a folder called “Template” under the file folder of your CodeFluent Entities project:

image

Right click on that folder and choose “Add existing item” then browse to your template file and select it.

Now in your CodeFluent Entities project, add an instance of the SQL Server Template Producer with your Template directory as the “Source Directory” and set the “Target Directory” to the project of you choice and then build over your model. The SQL Server Template Producer will generate a script file from your template, and run the script on the server removing and creating clustered indexes. Therefore using the template producer you can quickly create complex scripts by taking advantage of the meta model.

 

Cheers,

Thibault NESTOR

Generating unit test skeleton using the Template Producer

November 26, 2012 1 comment

We already introduced the Template Producer in a previous post with a small example showing how to generate a DGML graph from a CodeFluent Entities model. This post is another example to remind you how easy it is to generate text files using the Template Producer whilst accessing the inferred meta-model.

Let’s say we’d like to generate a skeleton for our unit tests. By skeleton I mean a vb or csharp file by entity that will contain test methods ready to be implemented.

Assuming we are writing a pretty simple bank application. Our model has an “Account” entity and 3 methods (to deposit, withdraw, and transfer funds) as follow:

image

Supposing we’re using Nunit as unit-testing framework, let’s create our template to be used by the Template Producer:

    1. Add a new folder called Templates into the File folder
      ScreenShot047
    2. Add it a new text file (Ctrl+shift+A) called “[Template]UnitTests.tplScreenShot049
    3. Past it the following code describing our skeleton:
[%@ namespace name="System"%]
[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Code"%]
[%@ template enumerable='Producer.Project.Entities' enumerableItemName="entity" enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), String.Format("{0}Tests", entity.ClrFullTypeName)) + ".cs"' %]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace [%= entity.Namespace %]
{
    [TestFixture]
    public class [%= String.Format("{0}Tests", entity.Name) %]
    {
        [SetUp]
        public void Init()
        {
            /* ... */
        }

        [TearDown]
        public void Cleanup()
        {
            /* ... */
        }

        [% foreach(Method m in entity.Methods) { if (!m.Enabled) continue; %]
            [Test]
            [%= String.Format("public void {0}Test()", m.Name)  %]
            {
                /* ... */
            }
        [% } %]
    }
}

Basically, what the template does is that it iterates through all entities of the project as well as each method to write a file by entity containing a test class with all test methods.

  1. Create a class library project called Bank.UnitTests to store all your unit tests and add it a reference to Nunit framework.
  2. Add a Template Producer and set the Source directory to your Templates folder created earlier and the Target directory to the Bank.UnitTests project.

The Template Producer instance will execute all templates placed in the Templates directory, and place output files in the Bank.UnitTests project directory.

Building your model should produce one file called Bank.AccountTests.cs with all the test methods ready to be implemented:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace Bank
{
    [TestFixture]
    public class AccountTests
    {
        [SetUp]
        public void Init()
        {
            /* ... */
        }

        [TearDown]
        public void Cleanup()
        {
            /* ... */
        }

        [Test]
        public void DepositTest()
        {
            /* ... */
        }

        [Test]
        public void WithdrawTest()
        {
            /* ... */
        }

        [Test]
        public void TransferFundsTest()
        {
            /* ... */
        }

    }
}

As you can see, this short and simple example gives you an idea of what it is possible to do by taking advantage of the meta model using the Template Producer.

Want to know more? You’ll find more information on the Template Producer here.

Cheers,

Thibault NESTOR

Generating a WPF Smart Client using the Smart Client Producer

October 22, 2012 Leave a comment

Hello!

In a previous posts, we showed you the output of the WPF Smart Client Producer. In this post we’ll show you how to generate a WPF smart client. It will be a WPF application consuming WCF services thanks to a proxy and the data will be stored in a database Smile.

Creating the solution

Start by creating a new CodeFluent Project. We’ll use the “ContactManager Sample Model” for the purpose of this article.ContactManagerModel

Add a new Class Library project named “ContactManager” to your solution. It will be used to host the generated files corresponding to your Business Object model and WCF service’s contracts. Add it a folder called “ServicesConfig” that will be used to store your WCF service’s configuration files.

Add a new Class Library project named “ContactManager.Proxy” to your solution. It will be used to host the generated files corresponding to the proxy.

Add a new SQL Server Database project named “ContactManager.Persistence” to your solution. It will be used to host your generated SQL scripts.

Add a new WPF application project named “ContactManager.SmartClient” to your solution. It will be used to host the generated files of your WPF application. Remove the MainWindow.xaml file since we are going to generate our own. Also, by default, Microsoft Visual Studio 2010 sets the target framework to .NET Framework 4 Client Profile. Go to the property of your project and change the target to .NET Framework 4 in order to use the standard libraries.

image

Adding the producers

The Business Object Model Producer

To generate your Business Objects model, add the Business Object Model Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:

image

In the Target Directory field, select your Class Library project called ContactManager.

image

Click OK.

The SQL Server Producer

To generate your persistence scripts, add the SQL Server Producer (or the one that suits your configuration) to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Persistence Layer Producers node and select it:

image

In the Connection String field enter your connection string used to connect to your SQL Server. Also in the Target Directory field, select your SQL Server Database project called ContactManager.Persistence. Finally in the Target Version field, select your SQL Server version.

The Service Object Model Producer

To generate your WCF service and your proxy, add the Service Object Model Producer to your CodeFluent Entities project by clicking “Add new SubProducer” on your  “Business Object Model” producer in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:

image

In the Target Directory field, select your Class Library project called ContactManager.Proxy and click OK.

The Template Producer

Note: The Template producer is not mandatory. However, it is really handy if you want to be able to quickly run and test your WCF service using the CodeFluent Entities Hoster.

Lets now generate the configuration files of your WCF service. Add the Template Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Utility Producers node and select it:

ScreenShot032

In the Source Directory field select the “Server” folder located at “CodeFluent Entities installation folder > Modeler >Templates > ServiceModel”. And in the Target Directory field, select the folder called ServicesConfig located in your Class Library project called ContactManager, then click OK.

The WPF Smart Client Producer

Then, to generate your WPF smart client, add the WPF Smart Client Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Application Producers node and select it:

image

In the Target Directory field, select your WPF application project called ContactManager.SmartClient and click OK.

Generating code

Now to start generating code, build your CodeFluent Entities project called ContactManager.Model.

Here is the visual studio solution you should have by now, each project containing the generated code (your database should have been created too):

image

Building and running the application

At this stage, your application has been generated and is almost ready to be built and run. Since your WPF application uses the Proxy you need to add your Class Library project called ContactManager.Proxy as a reference to your WPF application project called ContactManager.SmartClient project.

Now you can build your solution, then run your WCF service as you usually do or thanks to the CodeFluent Entities Hoster using your generated service configuration files. Finally start your WPF application.

Tip: If you use the CodeFluent Entities Hoster, a quick and easy way to ensure the executable is automatically copied to the output directory is to add a reference to it. This is absolutely not required to compile your Business Object model (your Class Library called ContactManager), it’s just a shortcut to have the executable in the output directory without having to create post-build events.

And tadaaa! You’ve created your 100% functional WPF smart client without a single line of code!

SmartClient (1)

SmartClient (2)

Enjoy!

Thibault Nestor

CodeFluent Entities: Writing a Template Generating One File Per Entity

February 16, 2012 1 comment

Following the previous post “Generating Custom Code For All Entities” a colleague showed me the greatest way ever to iterate on a collection of concepts and generate text a file for each from a template, so I thought I’d share it Smile

In this post we’ll write a template to generate a C# file per entity extending the one generated by the Business Object Model producer. The generated file should look like this one:

namespace Sample
{
    public partial class Customer
    {
        public static Customer LoadFromLob(string entityKey)
        {
            // TODO: load from external LOB
        }
    
        public void SendToLob()
        {
            // TODO: save current instance to external LOB
        }
    }
}

 

To generate code like the one above I created a template file named “[Template]entity.tpl”.

Note: The “[Template]” prefix is important as it indicates the producer to run the template. Other than that, the rest of the name doesn’t matter as we’ll name our output files <EntityName>.g.cs and this will be done in the template.

Here’s my template:

[%@ template enumerable='Producer.Project.Entities' enumerableItemName="entity" enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), entity.Name) + ".g.cs"' %]
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the Template Producer.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace [%=entity.Namespace%]
{
    public partial class [%=entity.Name%]
    {
        public static [%=entity.Name%] LoadFromLob(string entityKey)
        {
            // TODO: load from external LOB
        }
    
        public void SendToLob()
        {
            // TODO: save current instance to external LOB
        }
    }
}

Instead of all the code which we used to have I now have a single line which will have the exact same effect. Here’s a description of what it does:

  • the enumerable attribute takes an IEnumerable as an input. In our case, I’ve set it to take as input all entities of my project. This is possible as all producers have a Project property corresponding to the model inferred from your model.
  • the enumerableItemName attribute corresponds to the item name which I named “entity” as I’m enumerating on all entities. That’s basically the variable name of my foreach, and that’s how I can use the “entity” variable in the rest of my template.
  • the enumerableTargetPathFunc is a code snippet to be called to compute the target path of the generated file. This is thanks to this snippet that I’m generating files named as “<EntityName>.g.cs”.

Running my new template, here’s the result:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the Template Producer.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Sample
{
    public partial class Customer
    {
        public static Customer LoadFromLob(string entityKey)
        {
            // TODO: load from external LOB
        }
    
        public void SendToLob()
        {
            // TODO: save current instance to external LOB
        }
    }
}

 

Carl Anderson

Categories: Templates Tags: ,

CodeFluent Entities: Generating Custom Code For All Entities

February 15, 2012 3 comments

We often have questions on our forums of CodeFluent Entities users who’d like to add custom methods to all entities of their project.

A convenient way to do this is by writing a template of those custom methods and run them on all entities, and this is what we’ll see in this post.

Scenario

Say I have some line of business, external to my application, but with which every now and then I want to be able to synchronize my generated classes. As a consequence, I’d like all my entity classes to have two extra methods: a SendToLob and LoadFromLob.

Solution

To do so we’re going to write a template which, for each entity, will add those two methods in a partial class, extending the generated code. To do so we’ll create a single template which will create one .CS file for each entity.

Here’s our template (named “[Template]entity.g.cs”):

[%@ template language="CSharp" output="false"%]
[%@ namespace name="System" %]
[%@ namespace name="CodeFluent.Model" %]
[%@ namespace name="CodeFluent.Producers.CodeDom" %]
[%@ namespace name="CodeFluent.Model.UI" %]
[%@ namespace name="CodeFluent.Model.UI.ControlDefinitions" %]
[%@ namespace name="CodeFluent.Producers.CodeDom.UI" %]
[%@ namespace name="System.IO" %]
[%

Entity entity = null;
if (Context["inTemplate"] == null)
{
    Context["inTemplate"] = true; // anything would do, other than null
    foreach(Entity e in Producer.Project.Entities)
    {
        // build a new target path & re-run ourselves
        string targetPath = Path.Combine(
            Path.GetDirectoryName(TargetPath),
            Path.GetFileName(TargetPath).Replace("entity", e.Name));
        using (GeneratedFile file = new GeneratedFile(Producer.Project, targetPath))
        {
            if ((file.HasBeenChanged) && ((e.ProductionFlags & ProductionFlags.Overwrite) == 0))
            {
                Producer.RaiseProduction(Producer, file.CreateFileSkipEvent("entity.g.cs"));
                continue;
            }

            // note: we don't care about the output="false" here
            Producer.RaiseProduction(Producer, ProductionEventArgs.CreateFileTemplateGenerateEvent(targetPath, Template.FilePath));
            file.Open(Producer, Producer.OutputEncoding);

            // add the entity to the context
            Context["entity"] = e;

            // update targetPath
            Context["TargetPath"] = targetPath;

            // go recursive, and this will jump to the else part of this file
            Template.Run(file.Writer, Context);
        }
    }
}
else
{
    entity = (Entity)Context["entity"];
%]
namespace [%=entity.Namespace%]
{
    public partial class [%=entity.Name%]
    {
        public static [%=entity.Name%] LoadFromLob(string entityKey)
        {
            // TODO: load from external LOB
        }

        public void SendToLob()
        {
            // TODO: save current instance to external LOB
        }
    }
}
[% }%]

The first part of the template iterates on all entities, and re-runs itself to create a file where the “entity” file name was replaced by the actual entity name. The second part of the template is the actual code to be placed in the generated file.

Then:

  • Add an instance of the Template Producer to your model,
  • Set its source directory to point to the directory containing our [Template]entity.g.cs file,
  • Set its target directory to be the same as your Business Object Model Producer so the generated classes will be in the same directory.

You’re now ready to go, generate over!

Result

Extra files were generated (one per entity) extending your already existing generated classes:

image

And here’s the content of the Customer.g.cs file:

namespace Sample
{
    public partial class Customer
    {
        public static Customer LoadFromLob(string entityKey)
        {
            // TODO: load from external LOB
        }

        public void SendToLob()
        {
            // TODO: save current instance to external LOB
        }
    }
}

Remarks

Drawbacks of this method are that:

  • it creates one extra file per entity,
  • if entity classes are generated in subfolders (e.g. multiple namespaces) it will require extra code to handle.

Other options to obtain the same output but without those drawbacks could be to:

  • Generate a single class file extending all classes (a little ugly, yet so effective Smile)
  • Create a CodeFluent Aspect instead of using templates to add code snippets to all entities!

Hope this helps,

Carl Anderson

Categories: Templates Tags: ,

CodeFluent Entities: Using the SQL Server Template Producer to generate a script

December 26, 2011 3 comments

In this post we’ll see how using CodeFluent Entities’ SQL Server Template Producer, you can generate SQL scripts using  the built-in template engine whilst accessing the inferred meta-model, and then automatically deploy the generated script on your desired server.

In this particular scenario, a customer wanted to be able to version his generated stored procedures so his DBA could easily spot those that are of an other version. There are no built-in feature to do this natively using CodeFluent Entities, however versioning your stored procedures can be done with a few lines of code using the SQL Server Template Producer.

First we’ll write a script adding an extended property named “ModelVersion” on a generated stored procedure:

BEGIN TRY
    exec sp_addextendedproperty
        @name = N’ModelVersion’,
        @value = ‘<Version>’,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘Test_Load’;
END TRY
BEGIN CATCH
    exec sp_dropextendedproperty
        @name = N’ModelVersion’,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘Test_Load’;
    exec sp_addextendedproperty
        @name = N’ModelVersion’,
        @value = ‘<Version>’,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘Test_Load’;
END CATCH
GO

Note: I apologize to all DBAs out there, this script is just a quick and dirty way to create extended properties and overwrite the existing one if ever it already exists.

Now that we have our working script we’re going to turn it into a template which the SQL Server Template Producer will run:

[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Persistence"%]
/* [%=Producer.GetSignature()%] */
[% foreach (Procedure procedure in Producer.Project.Database.Procedures) { %]
BEGIN TRY
    exec sp_addextendedproperty
        @name = N’ModelVersion’,
        @value = ‘[%=Producer.Project.ModelCheckSum%]‘,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘[%=procedure.Name%]‘;
END TRY
BEGIN CATCH
    exec sp_dropextendedproperty
        @name = N’ModelVersion’,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘[%=procedure.Name%]‘;
    exec sp_addextendedproperty
        @name = N’ModelVersion’,
        @value = ‘[%=Producer.Project.ModelCheckSum%]‘,
        @level0type = N’Schema’, @level0name = ‘dbo’,
        @level1type = N’Procedure’,  @level1name = ‘[%=procedure.Name%]‘;
END CATCH
GO
[% } %]

As you can see this template iterates throughout all procedures of the virtual database inferred from my model, and adds a ModelVersion extended property.

Now in your CodeFluent Entities project, add an instance of the SQL Server Template Producer with your template directory as the “Source Directory” and build over your model. The SQL Server Template Producer will generate a script file from your template, and run the script on the server. Using SQL Server Management Studio we’ll now see our extended properties on all our generated stored procedures:

image

 

Carl

Generating Documentation

April 26, 2011 Leave a comment

CodeFluent Entities provides a documentation sub-producer which allows you to:

  • Decorate all members with XML comments (usable by Visual Studio IntelliSense and help tools),
  • Generate XML, batch and configuration files to create a .CHM documentation using Sandcastle.

To benefit from it, you first need to add an instance of the sub-producer. To do so, select the Business Object Model Producer instance of your project, right-click on it and select “Add New SubProducer”. Then in the “Add New SubProducer” dialog, select “Documentation” in the tree view and configure it:

DocumentationProducer

Note: the only required property is the “Sandcastle Target Directory “which needs to be specified so the producer knows where to generate its output files. If producing Sandcastle files, you need to have Sandcastle installed before generating and ensure the Sandcastle path is correct so you’ll be able to use the generated files right away.

Since decorating all members of all your generated classes all the time can be quite an overkill during developments, it is disabled by default in the Business Object Model producer, so you need to enable it as well. Double-click on your Business Object Model producer instance to open its configuration and set “Generate Xml Documentation” to “True”:

GenerateDocumentation

In the XML this looks like something like that:

<cf:producer typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">
  <cf:configuration targetDirectory="..\Sample" outputName="{0}.dll" generateDocumentation="true">
    <subProducer typeName="CodeFluent.Producers.Documentation.DocumentationProducer, CodeFluent.Producers.Documentation"
                 targetDirectory="..\Doc" sourceDirectory="%CF_TEMPLATES_PATH%\Documentation" />
  </cf:configuration>
</cf:producer>

Build over your project and you’ll see that all your members have XML remarks on them! Moreover, in the Sandcastle Target Directory you specified, you’ll see a set of files allowing you to generate a .CHM file documenting the generated objet model Smile

Follow

Get every new post delivered to your Inbox.

Join 41 other followers