Database Agnostic Model Template with dapper flavour

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

Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Fri 20 Apr 2018 16:04

This is continuation of my previous thread as trying to implement a custom model that will help me create model layer for many apps based on database.

Currently I am able to generate my main model files (partial model and generated partial model).

this is my current 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="Model" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelGeneratedOutput" displayName="Model Generated" category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelPartialOutput"  displayName="Model Empty Partial"  category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="ModelDapperNameSpace" displayName="Dapper Model namespace" category="Dapper" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelDapperGeneratedOutput" displayName="Dapper Model Generated" category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelDapperPartialOutput"  displayName="Dapper Model Empty Partial"  category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="MetaModelNameSpace" displayName="Meta Model namespace" category="Meta" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="MetaModelrGeneratedOutput" displayName="Meta Model Generated" category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="MetaModelPartialOutput"  displayName="Meta Model Empty Partial"  category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="InterfaceNameSpace" displayName="Interface namespace" category="Interface" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="InterfaceGeneratedOutput" displayName="Interface Generated" category="Interface"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="InterfacePartialOutput"  displayName="Interface Empty Partial"  category="Interface"  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(ModelPartialOutput, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelGeneratedOutput,  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



    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+}#>



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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Fri 20 Apr 2018 16:24

Currently I seem unable to go on...

I have a private method to run my class generation.. and another one which is invoked on my class generation to run properties generation...

adding this last one was as if template was invalid....
Severity Code Description Project File Line Suppression State
Error Custom tool error: Template 'ow.data.model' is not valid. Cannot unparse template. D:\GIT\ow\OWOW\server\api\ow.manager\ow.manager.Data.ED\DataModel.edml 1
I wonder what I am doing wrong.. if someone on devart side is monitoring on this forum I would like some help, please.

my 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" #>
<#@ 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="Model" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelGeneratedOutput" displayName="Model Generated" category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelPartialOutput"  displayName="Model Empty Partial"  category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="ModelDapperNameSpace" displayName="Dapper Model namespace" category="Dapper" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelDapperGeneratedOutput" displayName="Dapper Model Generated" category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelDapperPartialOutput"  displayName="Dapper Model Empty Partial"  category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="MetaModelNameSpace" displayName="Meta Model namespace" category="Meta" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="MetaModelrGeneratedOutput" displayName="Meta Model Generated" category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="MetaModelPartialOutput"  displayName="Meta Model Empty Partial"  category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="InterfaceNameSpace" displayName="Interface namespace" category="Interface" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="InterfaceGeneratedOutput" displayName="Interface Generated" category="Interface"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="InterfacePartialOutput"  displayName="Interface Empty Partial"  category="Interface"  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(ModelPartialOutput, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelGeneratedOutput,  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 C
//
// 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( Property property in cls.Properties )  Generate_POCO_Property( property ) ; #> 

    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+}#>

<#+ private void Generate_POCO_Property( Property property ) {


    #>

<#+
    
}#>



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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Fri 20 Apr 2018 16:49

As I lost ttrack in small changes I do while trying to keep to work... not sure if this is same state than previously.

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="Model" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelGeneratedOutput" displayName="Model Generated" category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelPartialOutput"  displayName="Model Empty Partial"  category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="ModelDapperNameSpace" displayName="Dapper Model namespace" category="Dapper" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelDapperGeneratedOutput" displayName="Dapper Model Generated" category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelDapperPartialOutput"  displayName="Dapper Model Empty Partial"  category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="MetaModelNameSpace" displayName="Meta Model namespace" category="Meta" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="MetaModelrGeneratedOutput" displayName="Meta Model Generated" category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="MetaModelPartialOutput"  displayName="Meta Model Empty Partial"  category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="InterfaceNameSpace" displayName="Interface namespace" category="Interface" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="InterfaceGeneratedOutput" displayName="Interface Generated" category="Interface"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="InterfacePartialOutput"  displayName="Interface Empty Partial"  category="Interface"  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(ModelPartialOutput, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelGeneratedOutput,  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 A
//
// 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( Property property in cls.Properties ) Generate_POCO_Property( property );  #>

    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+}#>

<#+ private void Generate_POCO_Property( Property property ) {
    
    } #>
I am currently having this error:
Severity Code Description Project File Line Suppression State
Error Custom tool error: An error occurred during an attempt to compile the template 'ow.data.model'.
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\OWOW\server\api\ow.manager\ow.manager.Data.ED\ow.data.model.tmpl 1
I wonder... does entity developer templates are able to have more than 2 function/method levels?
Is someone able to anser this question?

thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by Shalex » Wed 25 Apr 2018 09:23

Your template with a correction is:

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="Model" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelGeneratedOutput" displayName="Model Generated" category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelPartialOutput"  displayName="Model Empty Partial"  category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="ModelDapperNameSpace" displayName="Dapper Model namespace" category="Dapper" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelDapperGeneratedOutput" displayName="Dapper Model Generated" category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelDapperPartialOutput"  displayName="Dapper Model Empty Partial"  category="Dapper"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="MetaModelNameSpace" displayName="Meta Model namespace" category="Meta" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="MetaModelrGeneratedOutput" displayName="Meta Model Generated" category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="MetaModelPartialOutput"  displayName="Meta Model Empty Partial"  category="Meta"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>

<#@ property name="InterfaceNameSpace" displayName="Interface namespace" category="Interface" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="InterfaceGeneratedOutput" displayName="Interface Generated" category="Interface"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="InterfacePartialOutput"  displayName="Interface Empty Partial"  category="Interface"  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(ModelPartialOutput, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelGeneratedOutput,  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 A
//
// 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( Property property in cls.Properties ) 
        Generate_POCO_Property( property );  
#>

    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+
}
#>
<#+ private void Generate_POCO_Property( Property property ) {
    
}
#>
The reason of the error you have encountered is extra CRLF between blocks.
It should be

Code: Select all

<#+
}
#>
<#+ private void Generate_POCO_Property( Property property ) {
    
}
#>
instead of

Code: Select all

<#+
}
#>

<#+ private void Generate_POCO_Property( Property property ) {
    
}
#>

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Tue 08 May 2018 00:13

Hi Shalex,

I am trying to raise my model template.
Currently I am stuck trying to parse all properties.... but not being able to go further on as there is an error for custom tool:
Severity Code Description Project File Line Suppression State
Error Custom tool error: An error occurred during an attempt to compile the template 'ow.model'.
Error List:
error : Invalid token 'this' in class, struct, or interface member declaration
error : Method must have a return type
error : Type expected C:\Demos\ow.API\ow.Data.Model\DataModel.POCO Entity.tmpl 1
currently my code is this:

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="Model" type="System.String" description="Specifies output namespace for the generated model entity classes." #>
<#@ property name="ModelGeneratedOutput" displayName="Model Generated" category="Model"  type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated model entity classes." #>
<#@ property name="ModelPartialOutput"  displayName="Model Empty Partial"  category="Model"  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(ModelPartialOutput, "", rootFileName, OverwriteMode.None);
      
      // generate empty partial
      GenerateEnmptyPartial(_namespace.Key, cls);
      output.PopOutputRedirection();

      // generate base class
      output.Extension = ".cs";
      output.PushOutputRedirection(ModelGeneratedOutput,  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 A
//
// 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( Property property in cls.Properties ) 
        Generate_POCO_Property( property );  
#>

    #endregion

    public <#= codeProvider.GetValidIdentifier(cls.Name) #>() {
    
    }
  }
}
<#+
}
#>
<#+ private void Generate_POCO_Property( Property property ) {

     string currentPropertyType = GetTypeName(property.Type, property.ParentClass.NamespaceUsed, property.Nullable);
     string propertyAccess = string.Empty;
     string getAccess = string.Empty;
     string setAccess = string.Empty;
     GetMemberAccessModifiers(property.Getter, property.Setter, ref propertyAccess, ref getAccess, ref setAccess);
     string inheritanceModifier = property.InheritanceModifier == MemberInheritanceModifier.None ? " virtual" : " " + codeProvider.FormatMemberInheritanceModifier(property.InheritanceModifier);
#>
  <#= propertyAccess #><#= inheritanceModifier #> <#= currentPropertyType #> <#= codeProvider.GetValidIdentifier(property.Name) #>
        {
            <#= getAccess #>get;
            <#= setAccess #>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;
  }
#>
perhaps you could help me on on my goal:
1 - I want to create a model entity from db with no reference to EF (the one currently under work)
2- an entity where I map a decoraton[Key] all primary keys of entity

Ath this point I am still not sure if I may join both (1, 2) on same model

3 - Create a second model where:
- Entities implement INotifyPropertyChanged (I suppose it is a copy of first one with changes on getters/setters);
- creating a string propertyProperty with property name;
- creating a property propertyMaxLengthProperty with max length of dtabase

PLease may you help me with this task?
Thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by Shalex » Thu 10 May 2018 17:26

figueiredorj wrote: Tue 08 May 2018 00:13 error : Invalid token 'this' in class, struct, or interface member declaration
error : Method must have a return type
error : Type expected C:\Demos\ow.API\ow.Data.Model\DataModel.POCO Entity.tmpl 1
The reason of the error is the same like before: you should remove extra CRLF between blocks (lines 139 and 140).
figueiredorj wrote: Tue 08 May 2018 00:13 perhaps you could help me on on my goal:
1 - I want to create a model entity from db with no reference to EF (the one currently under work)
Why don't you want to use a predefined POCO Entity template (Devart Entity Model)? It requires only few modifications (e.g.: remove generation EF namespaces in the head of the generated file).
figueiredorj wrote: Tue 08 May 2018 00:13 2- an entity where I map a decoraton[Key] all primary keys of entity
You can add any custom attribute to your model:
a) navigate to Model > Settings > Attributes > select the assembly with the needed attributes and make sure that the needed attributes are checked in the window below, press OK
b) select the needed attribute in the Attributes collection of a particular class property
figueiredorj wrote: Tue 08 May 2018 00:13 Ath this point I am still not sure if I may join both (1, 2) on same model
You can do that like described previously.
figueiredorj wrote: Tue 08 May 2018 00:13 3 - Create a second model where:
- Entities implement INotifyPropertyChanged (I suppose it is a copy of first one with changes on getters/setters);
This feature is implemented in a predefined POCO Entity template. Just set its Implement INotifyPropertyChanged property to True.
figueiredorj wrote: Tue 08 May 2018 00:13 - creating a string propertyProperty with property name;
- creating a property propertyMaxLengthProperty with max length of dtabase
The functionality is not clear. Please refer to the INotifyPropertyChanged implementation. Does this help?

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Sun 13 May 2018 12:14

Hi Salex,
many thanks for your ! :)

I wasn't aware of POCO template it self.

Putting all together of what you mentionated and some more research I am building a solution that fits my needs and eventually others.

Currently:
- I have a project where lives my datamodel and all definitions (this library doesn't ship on solution on my current build as I still haven't discarded datacontext- eventually removing it I may put it on Entities Project)
-- My Model.Entities ships on another project;

As dapper is mostly a sql orm, I may put all together without going any other third party dapper library. However for that to work I need to do reflection.

Using annotations validation I know which properties are keys; by exclusion, all other properties not mapped are Properties.
I need to add my classes 2 new string arrays:
- KeyPropertyNames
In a perfect world it would be Id - not the case;
- EntityPropertNames - All mapped name properties which are not keys on entity.

this will allow me to get all Properties Values withouth having to be requerying entity of which are his properties removing an extra overhead of processing it.

my Current template according to my needs:
(next post)

My interface IDataError

Code: Select all

    public interface IDataError
    {
        void ClearErrors();
        void ClearErrors(string property);
        void AddError(string property, string error);
        bool HasErrors { get; }
        IEnumerable GetErrors(string propertyName);

    }
Can You help me extract those 2 arrays?

Code: Select all

        
        public static string[] KeyProperties = {"Id's"};
        public static string[] EntityProperties = {"MappedNoKeys"};
Many thanks once again.
Wainting for your help.

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Sun 13 May 2018 12:23

Due to size of file I needed to link it:
https://1drv.ms/u/s!AuhmVET3Qp9ljTkwyG9SUxeKYEQp

And actually my EntityProperties is an array of all mapped properties... by their order.

public static string[] EntityProperties = {"MappedProperties"};

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Sun 13 May 2018 15:37

I have worked on what is my requirements and I am happy to say that I may have reached to what is my solution.
I have a small demo on what I am trying to achieve: https://1drv.ms/u/s!AuhmVET3Qp9ljTu--ArE6TSxyw5i

If you look into my class "Base" on model, I have 2 properties:

Code: Select all

        [NotMapped]
        public string[] KeyProperties => new string[] {"Id"};
        [NotMapped]
        public string[] EntityProperties => new string[] {"Id", "Code", "Description"};
This is what I am missing on template.
Can you help me?
thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Tue 15 May 2018 09:23

Hi Shalex,
while waiting for your help I have tried moving foward.

I have set this code on dbcontext:

Code: Select all

        #region Properties
<#
      var keyProperties = new List<string>();
      var entityProperties = new List<string>();
      
      foreach (EntityProperty property in cls.Properties){
          entityProperties.Add(property.Name);
          


          GenerateProperty(property);
          }


        
#>
          [NotMapped]
          public string[] EntityProperties { get; } = { <#= entityProperties.Aggregate((prev, next) => string.Format("\"{0}\"",prev) + "," + string.Format("\"{0}\"",prev) ) #> }
        #endregion
<#
However it throws Exception :
Severity Code Description Project File Line Suppression State
Error Custom tool error: Exception of type 'System.OutOfMemoryException' was thrown.
..\DataModel.edml 1
any clues?

Is this the right way to get my properties?
Also, how can I get my KeyProperties?

thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by Shalex » Wed 16 May 2018 17:12

EntityClass.Properties contains a collection of all class properties each of them is EntityProperty.
EntityProperty.PrimaryKey is a bool value to determine if it is a key or not.

If this doesn't help, reupload your current template and specify the issue you have encountered.

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

Re: Database Agnostic Model Template with dapper flavour

Post by Shalex » Wed 16 May 2018 17:16

Tips:
* use IntelliSense feature in our T4 Editor (completion list appears when you type the '.' character)
* you can switch to the model in design time to read a description of a particular property in the Properties window

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Wed 16 May 2018 22:11

Hi,
I did already figured what you said. ..
However I don't get why out of memory exception. .. I know it is not of the machine as it is 32 gb RAM :p. .. don't see any overflow. ..
Can you help me with that?

Thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by figueiredorj » Tue 22 May 2018 08:48

Hi Shalex,
any clue on what i9s giving me out of memory?

thanks

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

Re: Database Agnostic Model Template with dapper flavour

Post by Shalex » Tue 22 May 2018 09:20

figueiredorj wrote: Sun 13 May 2018 15:37I have a small demo on what I am trying to achieve: https://1drv.ms/u/s!AuhmVET3Qp9ljTu--ArE6TSxyw5i
figueiredorj wrote: Tue 22 May 2018 08:48any clue on what i9s giving me out of memory?
Please specify the exact steps we should follow with the custom template used in your project to reproduce System.OutOfMemoryException. If we should replace some T4 code, specify the line (a), current code (b), new code (c), any additional steps (d)?

Post Reply