Home > Templates > CodeFluent Entities: Generating Custom Code For All Entities

CodeFluent Entities: Generating Custom Code For All Entities


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: ,
  1. March 8, 2012 at 8:04 am

    Just a quick remark, after first generation you need to “include in project” generated files (“show all files” option on solution explorer then right-click on greyed files).

  2. SoftFluent
    April 12, 2012 at 8:34 am

    [Update] Although still functional, generating one file per class using this way is kind of obsolete. You can do it using a much simpler way which is detailed in this post: https://blog.codefluententities.com/2012/02/16/codefluent-entities-writing-a-template-generating-one-file-per-entity/

    Carl

  1. February 16, 2012 at 10:19 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s