Customizing Template for Dapper

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
Post Reply
figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Customizing Template for Dapper

Post by figueiredorj » Mon 16 Apr 2018 15:19

Hi,

I am trying to build a template in entity developer for dapper. For that I am picking in a POCO template.

However there is some rules which I don't know on how to modify/implement.

Rules:
  • Have interface
    nothing special on how to declare

    Code: Select all

    <#@ property name="GenerateInterface" category="Output" type="System.Boolean" default="False" description="If it is set to True, then, for each class in the model, a interface will be generated" #>
    <#@ property name="InterfaceOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated interfaces classes. The property can be used, if File GenerateInterface is turned on." #>
    <#@ property name="InterfaceNamespace" category="Generation" type="System.String" description="If this option is set, Interfaces will have this namespace" #>
    
  • Model
    Model is common class defined by getters and setters; only property "Keys" from database will be decorated. this is mapping class for Dapper
  • ModelExtended
    This is a business representation for some Applications related to business.
    There is some ambiguity related to this class as it Model implementing Bindable or INotifyPropertyChanging and INotifyPropertyChanged and Cloneable; this Could be Model and and opt for declaring previous Model as BaseModel.
  • MetaModel
    this is kind a validattion class that can be used by any application;
    It will describe PropertyNames

    Code: Select all

    public static string IdProperty = "Id";
    
    it will also describe default values when possible to apply

    Code: Select all

    public static int QuantityDefault = 0;
    and will describe maxLength when appliable

    Code: Select all

    public static int NameMaxLength = 50;
eventually it may be better to add partial classes so it may need to redefine something.

my idea is getting rid of EF declaration if possible (I think so).
Could you help me getting there?

Thanks

Shalex
Site Admin
Posts: 8182
Joined: Thu 14 Aug 2008 12:44

Re: Customizing Template for Dapper

Post by Shalex » Thu 19 Apr 2018 13:53

Dapper is currently not supported by Entity Developer, so there is no "out of the box" solution for your task.

You should modify any predefined template to get code generation you need. JIC: creation of interfaces is described at viewtopic.php?t=26147

figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Thu 19 Apr 2018 15:03

I already understood that and am working on it.

currently I have a very basic template, wich I was expecting to generate entities on Model Designer.
However nothing happens.

could you take a look and tell me what is wrong (ps. mailed @shalex).

Code: Select all

<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2018 Devart. All rights reserved.
#>
<#@ template language="C#" #>

<#@ include file="Validation.tmpl" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Xml" #>



<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="ModelNameSpace" displayName="Model namespace" category="Output" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>


<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName;

   string namespaceName = codeProvider.GetValidIdentifier(model.Namespace);

// Begin generation

  //------------------------------------------------------------------------------
  // Class generation for entities
  //------------------------------------------------------------------------------

  var namespaces = from cls in model.Classes.Cast<Class>()
    let nspName = !String.IsNullOrEmpty(cls.Namespace) ? codeProvider.GetValidIdentifier(cls.Namespace) : namespaceName
    group cls by nspName;

  // get namespaces?
  foreach (var _namespace in namespaces) {
  // get classes
    foreach (EntityClass cls in _namespace) {
      // handle class generation


      string rootFileName = cls.Name;

      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutput, "", rootFileName, OverwriteMode.None);

      #>

namespace <#= _namespace.Key #>
{

    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
    }
}
      
      <#

      output.PopOutputRedirection();
      }
  } 
// End of generation
#>
thanks

figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Thu 19 Apr 2018 15:27

ok.

now I already have evolved a little bit.
currently I am able to write a partial class of models in designer.

Code: Select all

<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2018 Devart. All rights reserved.
#>
<#@ template language="C#" #>

<#@ include file="Validation.tmpl" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Xml" #>



<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="ModelNameSpace" displayName="Model namespace" category="Output" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelOutputPartial" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>


<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName;

   string namespaceName = codeProvider.GetValidIdentifier(model.Namespace);

// Begin generation

  //------------------------------------------------------------------------------
  // Class generation for entities
  //------------------------------------------------------------------------------

  var namespaces = from cls in model.Classes.Cast<Class>()
    let nspName = !String.IsNullOrEmpty(cls.Namespace) ? codeProvider.GetValidIdentifier(cls.Namespace) : namespaceName
    group cls by nspName;

  // get namespaces?
  foreach (var _namespace in namespaces) {
  // get classes
    foreach (EntityClass cls in _namespace) {
      // handle class generation


      string rootFileName = cls.Name;

      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutputPartial, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);

      output.PopOutputRedirection();

      }
  } 
// End of generation
#>



<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GenerateEnmptyPartial(string _namespaceKey, EntityClass cls)
    {
#>
namespace <#= _namespaceKey #>
{
    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
    }
}
<#+
    }
#>


figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Fri 20 Apr 2018 09:46

Evolving on it:
Currently I am writing empty partial class on a "partialoutput" folder; my main class is on "output" folder.

going to add poco class properties

Code: Select all

<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2018 Devart. All rights reserved.
#>
<#@ template language="C#" #>

<#@ include file="Validation.tmpl" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Xml" #>



<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="ModelNameSpace" displayName="Model namespace" category="Output" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelOutputPartial" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>


<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName;

   string namespaceName = codeProvider.GetValidIdentifier(model.Namespace);

// Begin generation

  //------------------------------------------------------------------------------
  // Class generation for entities
  //------------------------------------------------------------------------------

  var namespaces = from cls in model.Classes.Cast<Class>()
    let nspName = !String.IsNullOrEmpty(cls.Namespace) ? codeProvider.GetValidIdentifier(cls.Namespace) : namespaceName
    group cls by nspName;

  // get namespaces?
  foreach (var _namespace in namespaces) {
  // get classes
    foreach (EntityClass cls in _namespace) {
      // handle class generation


      string rootFileName = cls.Name;

      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutputPartial, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutput,  rootFileName + ".Generated");

      //GeneratePocoClass(_namespace.Key, cls);
      GeneratePOCO(_namespace.Key, cls);
      output.PopOutputRedirection();

      }
  } 
// End of generation
#>



<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GenerateEnmptyPartial(string _namespaceKey, EntityClass cls)
    {#>
namespace <#= _namespaceKey #>
{
    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
    }
}
<#+
    }
#>
<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GeneratePOCO(string _namespaceKey, EntityClass cls)

    {#>
namespace <#= _namespaceKey #>
{
//------------------------------------------------------------------------------
// This is auto-generated code.
//------------------------------------------------------------------------------
// This code was generated by Devart Entity Developer tool using Entity Framework DbContext template.
//
// ow ED T4
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//------------------------------------------------------------------------------
  <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
  {

  }
}
<#+
    }
  
#>


figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Fri 20 Apr 2018 10:30

Don't get it.. always getting
Severity Code Description Project File Line Suppression State
Error Custom tool error: Custom tool error: An error occurred during an attempt to compile the template 'GiiC.Dapper'.
Error List:
error : Invalid token 'this' in class, struct, or interface member declaration
error : Method must have a return type
error : Type expected D:\GIT\ow\[OW]GiiC.API\source\GiiC.API\ow.GiiC.Data\ED\DataModel.edml 1
Unfortunately it seems quite random as same code works and doesn't work... depending on iteration...
current code:

Code: Select all

<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2018 Devart. All rights reserved.
#>
<#@ template language="C#" #>

<#@ include file="Validation.tmpl" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Xml" #>



<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="ModelNameSpace" displayName="Model namespace" category="Output" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelOutputPartial" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>


<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName;

   string namespaceName = codeProvider.GetValidIdentifier(model.Namespace);

// Begin generation

  //------------------------------------------------------------------------------
  // Class generation for entities
  //------------------------------------------------------------------------------

  var namespaces = from cls in model.Classes.Cast<Class>()
    let nspName = !String.IsNullOrEmpty(cls.Namespace) ? codeProvider.GetValidIdentifier(cls.Namespace) : namespaceName
    group cls by nspName;

  // get namespaces?
  foreach (var _namespace in namespaces) {
  // get classes
    foreach (EntityClass cls in _namespace) {
      // handle class generation


      string rootFileName = cls.Name;

      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutputPartial, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutput,  rootFileName + ".Generated");

      //GeneratePocoClass(_namespace.Key, cls);
      GeneratePOCO(_namespace.Key, cls);
      output.PopOutputRedirection();

      }
  } 
// End of generation
#>



<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GenerateEnmptyPartial(string _namespaceKey, EntityClass cls)
    {#>
namespace <#= _namespaceKey #>
{
    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
    }
}
<#+
    }
#>
<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GeneratePOCO(string _namespaceKey, EntityClass cls){#>
namespace <#= _namespaceKey #>
{
  //------------------------------------------------------------------------------
  // This is auto-generated code.
  //------------------------------------------------------------------------------
  // This code was generated by Devart Entity Developer tool using Entity Framework DbContext template.
  //
  // ow ED T4
  //
  // Changes to this file may cause incorrect behavior and will be lost if
  // the code is regenerated.
  //------------------------------------------------------------------------------
    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
      <#+ foreach(EntityProperty property in cls.Properties)  GenerateProperty_poco(property);#>

    }
}
<#+}#>

<#+ private void  GenerateProperty_poco(EntityProperty property) {
    
}#>
Any help?

figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Fri 20 Apr 2018 12:01

Now I am able to run template...
but once again.. how can I debug?

it seem to be ok, but no properties are being generated.. why?
my template:

Code: Select all

<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2018 Devart. All rights reserved.
#>
<#@ template language="C#" #>

<#@ include file="Validation.tmpl" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Xml" #>



<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="ModelNameSpace" displayName="Model namespace" category="Output" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelOutputPartial" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>


<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName;

   string namespaceName = codeProvider.GetValidIdentifier(model.Namespace);

// Begin generation

  //------------------------------------------------------------------------------
  // Class generation for entities
  //------------------------------------------------------------------------------

  var namespaces = from cls in model.Classes.Cast<Class>()
    let nspName = !String.IsNullOrEmpty(cls.Namespace) ? codeProvider.GetValidIdentifier(cls.Namespace) : namespaceName
    group cls by nspName;

  // get namespaces?
  foreach (var _namespace in namespaces) {
  // get classes
    foreach (EntityClass cls in _namespace) {
      // handle class generation


      string rootFileName = cls.Name;

      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutputPartial, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelOutput,  rootFileName + ".Generated");

      //GeneratePocoClass(_namespace.Key, cls);
      GeneratePOCO(_namespace.Key, cls);
      output.PopOutputRedirection();

      }
  } 
// End of generation
#>



<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GenerateEnmptyPartial(string _namespaceKey, EntityClass cls)
    {#>
namespace <#= _namespaceKey #>
{
    <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
    {
    }
}
<#+
    }
#>
<#+

  /// 
  /// Generates Class as Partial (Empty) for user declarations
  ///
private void GeneratePOCO(string _namespaceKey, EntityClass cls)

    {#>
namespace <#= _namespaceKey #>
{
//------------------------------------------------------------------------------
// This is auto-generated code.
//------------------------------------------------------------------------------
// This code was generated by Devart Entity Developer tool using custom template at <#= DateTime.Now #>
//
// ow ED T4
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//------------------------------------------------------------------------------
  <#= codeProvider.FormatClassAccess(cls.Access) #> partial class <#= codeProvider.GetValidIdentifier(cls.Name) #>
  {
    #region properties

<#+ foreach( EntityProperty property in cls.Properties ) GenerateProperty_poco( property ); #>

    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+}#>
<#+ private void GenerateProperty_poco( EntityProperty property ) {
    
    // Property code
    string currentPropertyType = GetTypeName(property.Type, property.ParentClass.NamespaceUsed, property.Nullable);

  #>
    //  <#= codeProvider.GetValidIdentifier(property.Name) #>
    public virtual <#= currentPropertyType #> <#= codeProvider.GetValidIdentifier(property.Name) #> { get; set; }
 <#+}#>

<#+
  //////////////////////////////////////////////////////////////////////////////////
  //
  // Utility methods
  //
  //////////////////////////////////////////////////////////////////////////////////

  private void WriteSemicolonAndNewLine() {

#>;
<#+
  }

    // Method GetTypeName
  private string GetTypeName(object type, string _namespace, bool nullable) {
    string dataType = string.Empty;
    if (type is ICodeElement) {
      dataType = codeProvider.GetValidIdentifier(((ICodeElement)type).Name);
	  if (!(type is EnumType && ((EnumType)type).IsExternal && string.IsNullOrEmpty(((ICodeElement)type).Namespace))) {
        string nspace = !string.IsNullOrEmpty(((ICodeElement)type).Namespace) ? ((ICodeElement)type).Namespace : model.Namespace;
        if (nspace != _namespace)
          dataType = codeProvider.GetValidIdentifier(nspace) + "." + dataType;
      }
      if (type is EnumType && nullable)
        dataType = codeProvider.FormatNullable(dataType);
    }
    else
      dataType = codeProvider.GetNullableType(nullable, type);
    return dataType;
  }

  // Method GetCodeElementReference
  private string GetCodeElementReference(ICodeElement element) {

    if (!string.IsNullOrEmpty(element.Namespace) && element.Namespace != model.Namespace)
      return codeProvider.GetValidIdentifier(element.Namespace) + "." + codeProvider.GetValidIdentifier(element.Name);
    return codeProvider.GetValidIdentifier(element.Name);
  }

  // Method IsValueType()
  private bool IsValueType(string propType) {

    Type t = Type.GetType(propType);
    return (t == null) ? false : t.IsValueType;
  } 

  // Method GetVariableName()
  private string GetVariableName(string name) {

    return codeProvider.GetValidIdentifier(name.Substring(0, 1).ToLower() + name.Substring(1));
  } 

  // Method GetMemberAccessModifiers()
  private void GetMemberAccessModifiers(MemberAccess propertyGetter, MemberAccess propertySetter, ref string propertyAccess, ref string getAccess, ref string setAccess) {

    if ((int)propertyGetter < (int)propertySetter) {
      propertyAccess = codeProvider.FormatMemberAccess(propertyGetter);
      setAccess = codeProvider.FormatMemberAccess(propertySetter) + " ";
    }
    else
      if (propertyGetter == propertySetter) {
        propertyAccess = codeProvider.FormatMemberAccess(propertyGetter);
      }
      else {
        propertyAccess = codeProvider.FormatMemberAccess(propertySetter);
        getAccess = codeProvider.FormatMemberAccess(propertyGetter) + " ";
      }
  }

  // Method GetMinimalClassAccess()
  private ClassAccess GetMinimalClassAccess(ClassAccess first, ClassAccess second) {

    return (int)first > (int)second ? first : second;
  }
#>




figueiredorj
Posts: 36
Joined: Fri 12 Apr 2013 19:05

Re: Customizing Template for Dapper

Post by figueiredorj » Fri 20 Apr 2018 16:01

Actually I am changing title scope of what I am doing...
I think I can draw more attention if my end result to be named as database agnostic although I have a model which will also been used by dapper.

but as my crud layer is not on same layer, I can say that I am doing some database agnostic model.
I will open a new thread as Database Agnostic Model Template with dapper flavour - I need a model with key annotation on primary keys.

Shalex
Site Admin
Posts: 8182
Joined: Thu 14 Aug 2008 12:44

Re: Customizing Template for Dapper

Post by Shalex » Wed 25 Apr 2018 09:24

We have answered you at viewtopic.php?f=32&t=37062.

Post Reply