Data Transfer Object (DTO) for EntityFramework doesn't contain inherited navigation properties

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
Post Reply
PeterM
Posts: 14
Joined: Tue 16 Jul 2013 12:53

Data Transfer Object (DTO) for EntityFramework doesn't contain inherited navigation properties

Post by PeterM » Thu 15 Jan 2015 09:10

Am I correct in concluding that the template to generate a Data Transfer Object (DTO) for EntityFramework doesn't contain Navigation properties of an entity that are inherited from its base?

I've been trying to solve this issue myself in the template but the 'cls.RelationProperties' that is used in the GetActiveRelationProperties appears to be lacking relations that come from a base class (the base of the somewhat confusingly named baseClass actually).

Could this be retrieved somewhere, or should the RelationProperties property simply contain those and did I mess it up configuration wise or some other way?

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

Re: Data Transfer Object (DTO) for EntityFramework doesn't contain inherited navigation properties

Post by Shalex » Mon 19 Jan 2015 14:00

PeterM wrote:Am I correct in concluding that the template to generate a Data Transfer Object (DTO) for EntityFramework doesn't contain Navigation properties of an entity that are inherited from its base?
That is correct.
PeterM wrote:Could this be retrieved somewhere [...]?
You can modify a predefined Data Transfer Object template by adding the following code in the private List<RelationProperty> GetActiveRelationProperties(BaseClass baseClass) method to add Navigation properties to an entity that is inherited from its base:

Code: Select all

    var relationProperties = cls.RelationProperties
      .Where(rp => rp.Generate &&
                   (bool)rp.GetProperty("GenerateDTO") &&
                   (bool)rp.Association.GetProperty("GenerateDTO")).ToList();
     
     while(cls.BaseClass != null) {
      cls = cls.BaseClass;
      relationProperties.AddRange(cls.RelationProperties
      .Where(rp => rp.Generate &&
                   (bool)rp.GetProperty("GenerateDTO") &&
                   (bool)rp.Association.GetProperty("GenerateDTO")));
    }
The full code of updated template:

Code: Select all

<#
// Data Transfer Object template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2015 Devart. All rights reserved.
#>
<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#
  //------------------------------------------------------------------------------
  // Template properties:
  //------------------------------------------------------------------------------

  // Output options
#>
<#@ property name="FilePerClass" category="Output" type="System.Boolean" default="false" description="If it is set to True, each DTO class will be placed to the separate file when generating code, otherwise, all DTO classes will be placed into a single file." #>
<#@ property name="DtosOutput" displayName="DTO Output" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated DTO classes." #>
<#@ property name="ConvertersOutput" category="Output" type="OutputInfo" editor="OutputInfoEditor" description="Specifies output for the generated DTO converter classes." #>
<#@ property name="GeneratePartialDtos" displayName="Generate Partial DTOs" category="Output" type="System.Boolean" default="false" description="If it is set to True, then, for each DTO class a partial class will be generated, in which the user can add code that is not overwritten by the designer." #>
<#@ property name="GeneratePartialConverters" category="Output" type="System.Boolean" default="false" description="If it is set to True, then, for each DTO converter class a partial class will be generated, in which the user can add code that is not overwritten by the designer." #>
<#
  // Common generation options
#>
<#@ property name="DtoNamespace" displayName="DTO Namespace" category="Generation" type="System.String" description="Specifies namespace for the generated DTO classes." #>
<#@ property name="HeaderTimestampVersionControlTag" category="Generation" type="System.String" description="If this option is set, the standard date/time-stamp in the file header will be replaced with the specified tag (e.g. a version control tag for Subversion, Git, etc.)" #>
<#
  // DTO classes generation options
#>
<#@ property name="DtoClassNamePrefix" displayName="DTO Class Name Prefix" category="DTO Classes" type="System.String" default="" description="If this property is set, when generating a DTO class name, the value of this property is added to the name as a prefix." #>
<#@ property name="DtoClassNameSuffix" displayName="DTO Class Name Suffix" category="DTO Classes" type="System.String" default="Dto" description="If this property is set, when generating a DTO class name, the value of this property is added to the name as a suffix." #>
<#@ property name="WcfDataContractAttributes" displayName="WCF Data Contract Attributes" category="DTO Classes" type="System.Boolean" default="True" description="If it is set to True, WCF Data Contract attributes will be generated." #>
<#@ property name="WcfDataMemberOnNavigationProperties" displayName="WCF DataMember Attribute on Navigation Properties" default="All" category="DTO Classes" type="WcfDataMemberGenerationBehavior" description="Specifies when the DataMember attribute must be generated for navigation properties. This property is used when 'WCF Data Contract Attributes' is set to true. By default the DataMember attribute is always generated if 'WCF Data Contract Attributes' is set to true." #>
<#@ property name="GenerateDtoConstructors" displayName="DTO Constructors" category="DTO Classes" type="System.Boolean" default="True" description="If it is set to True, DTO class constructors are generated." #>
<#@ property name="UseDtoClassesInAssociations" displayName="DTO Classes In Associations" category="DTO Classes" type="System.Boolean" default="True" description="If it is set to True, navigation properties for DTO classes are generated on any association end. These properties are generated as single DTO Objects (for a (0..1) or (1) association end) or collections of DTO objects (for a (*) association end). If it is set to False, The navigation properties for DTO classes are generated only for (*) association ends. If the dependent class has a simple primary key that consists of a single property, the navigation property is a collection of primitive type elements (for example, List<Int32>), that are the primary key values of the dependent class. If the primary key of the dependent class consists of several properties, the navigation property is a collection of new DTO class objects (for example, List<OtherClassKeyDto>), that contain only the primary key properties of the dependent class. If the dependent class does not have a primary key, the navigation property is a collection of the existing DTO class (for example, List<OtherClassDto>)." #>
<#
  // DTO Conversion generation options
#>
<#@ property name="GenerateConverters" category="DTO Conversion" type="System.Boolean" default="True" description="If it is set to True, DTO converter classes will be generated." #>
<#@ property name="ConverterClassNamePrefix" category="DTO Conversion" type="System.String" default="" description="If this property is set, when generating a DTO converter class name, the value of this property is added to the name as a prefix." #>
<#@ property name="ConverterClassNameSuffix" category="DTO Conversion" type="System.String" default="Converter" description="If this property is set, when generating a DTO converter class name, the value of this property is added to the name as a suffix." #>
<#
  // Extended properties for model objects
#>
<#@ extended name="GenerateDTO" type="System.Boolean" default="True" owner="Class" description="Defines whether to generate Data Transfer Object (DTO) class for this entity." #>
<#@ extended name="GenerateDTO" type="System.Boolean" default="True" owner="ComplexType" description="Defines whether to generate Data Transfer Object (DTO) class for this complex type." #>
<#@ extended name="GenerateDTO" type="System.Boolean" default="True" owner="Property" description="Defines whether to include this property in generated Data Transfer Object (DTO) class." #>
<#@ extended name="GenerateDTO" type="System.Boolean" default="True" owner="RelationProperty" description="Defines whether to include this relation property in generated Data Transfer Object (DTO) class." #>
<#@ extended name="GenerateDTO" type="System.Boolean" default="True" owner="Association" description="Defines whether to include this association in generated Data Transfer Object (DTO) classes." #>
<#
  //------------------------------------------------------------------------------

  // Settings
  output.Extension = ".cs";
  output.AddReference("System.Runtime.Serialization");
  baseFileName = model.FileName;

  string defaultNamespace = codeProvider.GetValidIdentifier(model.GetDefaultNamespace());
  string dtosNamespace = !string.IsNullOrEmpty(DtoNamespace) ? codeProvider.GetValidIdentifier(DtoNamespace) : defaultNamespace;

  // Generation

  List<BaseClass> entities = model.Classes
      .Where(cls => (bool)cls.GetProperty("GenerateDTO"))
      .Cast<BaseClass>()
    .Union(model.ComplexTypes
      .Where(complexType => (bool)complexType.GetProperty("GenerateDTO"))
      .Cast<BaseClass>()
    )
    .ToList();

  //------------------------------------------------------------------------------
  // Class generation for DTOs
  //------------------------------------------------------------------------------
  
  if (!FilePerClass) {
    output.PushOutputRedirection(DtosOutput, baseFileName + ".DTOs");
    output.AddReference("System.Runtime.Serialization");
    GenerateDtoFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
  }

  foreach (BaseClass cls in entities) {
    string dtoClassName = GetDtoClassName(cls);
    if (FilePerClass) {
      string rootFileName = dtoClassName;
      if (GeneratePartialDtos) {
        output.Extension = ".cs";
        output.PushOutputRedirection(DtosOutput, "", rootFileName, OverwriteMode.None);		
#>

namespace <#= dtosNamespace #>
{

    public partial class <#= codeProvider.GetValidIdentifier(dtoClassName) #>
    {
    }
}
<#
        output.PopOutputRedirection();
      }

      output.Extension = ".cs";
      if (GeneratePartialDtos)
        output.PushOutputRedirection(DtosOutput, rootFileName, rootFileName + ".Generated");
      else
        output.PushOutputRedirection(DtosOutput, rootFileName);
	    output.AddReference("System.Runtime.Serialization");
      GenerateDtoFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
    }
#>

<#
    GenerateWcfDataContractAttributeIfNeeded();

 
    string currentClassName = codeProvider.GetValidIdentifier(dtoClassName); 
#>
    public partial class <#= currentClassName #>
    {
<#

    List<Property> properties = GetActiveProperties(cls);
    List<RelationProperty> relationProperties = GetActiveRelationProperties(cls);

    GenerateAllDtoConstructors(cls, currentClassName, properties, relationProperties);
    GenerateAllProperties(properties);
    GenerateAllRelationProperties(relationProperties);
#>
    }
<#
    if (FilePerClass) {
#>

}
<#
      output.PopOutputRedirection();
    }

  } // End of DTO class generation

  // DTO key class generation
  if (!UseDtoClassesInAssociations) {
    foreach (BaseClass cls in this.NewDtosWithComplexPk) {
      string dtoKeyName = GetDtoKeyClassName(cls);
      List<Property> idProperties = GetKeyProperties(cls);

      if (FilePerClass) {
        output.PushOutputRedirection(DtosOutput, dtoKeyName);
        GenerateDtoFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
      }

      string dtoKeyClassName = codeProvider.GetValidIdentifier(dtoKeyName);
#>

<#
      GenerateWcfDataContractAttributeIfNeeded();
#>
    public partial class <#= dtoKeyClassName #>
    {
<#
      GenerateAllProperties(idProperties);
#>
    }
<#
      if (FilePerClass) {
#>

}
<#
        output.PopOutputRedirection();
      }
    }
  } // End of DTO key class generation

  if (!FilePerClass) {
#>

}
<#
  }
  // End of DTO classes generation

  //------------------------------------------------------------------------------
  // Class generation for DTO converters
  //------------------------------------------------------------------------------
  
  if (GenerateConverters) {

    if (!FilePerClass) {
      output.PushOutputRedirection(ConvertersOutput, baseFileName + ".Converters");
      GenerateConverterFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
    }

    foreach (BaseClass cls in entities) {

      Class realClass = cls as Class;
      if (realClass != null && realClass.IsAbstract)
        continue;

      string dtoClassName = GetDtoClassName(cls);
      string converterClassName = ConverterClassNamePrefix + cls.Name + ConverterClassNameSuffix;
      if (FilePerClass) {
        string rootFileName = converterClassName;
        if (GeneratePartialConverters) {
          output.Extension = ".cs";
          output.PushOutputRedirection(ConvertersOutput, "", rootFileName, OverwriteMode.None);
#>

namespace <#= dtosNamespace #>
{

    public static partial class <#= codeProvider.GetValidIdentifier(converterClassName) #>
    {
    }
}
<#
          output.PopOutputRedirection();
        }

        output.Extension = ".cs";
        if (GeneratePartialConverters)
          output.PushOutputRedirection(ConvertersOutput, rootFileName, rootFileName + ".Generated");
        else
          output.PushOutputRedirection(ConvertersOutput, rootFileName);
        GenerateConverterFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
      }
#>

    public static partial class <#= codeProvider.GetValidIdentifier(converterClassName) #>
    {
<#
      string entityClassName = GetCodeElementReference(cls);
      List<Property> allProperties = GetActiveProperties(cls);
      List<RelationProperty> relationProperties = GetActiveRelationProperties(cls);
#>

        public static <#= dtoClassName #> ToDto(this <#= entityClassName #> source)
        {
            return source.ToDtoWithRelated(0);
        }
<#
      ConverterSingleObjectWithRelatedCopyMethod(allProperties, relationProperties, "ToDto", "ToDtoWithRelated", "ToDtosWithRelated", entityClassName, dtoClassName, "OnDtoCreating");
      ConverterSingleObjectCopyMethod(allProperties, relationProperties, "ToEntity", dtoClassName, entityClassName, "OnEntityCreating");
      ConverterCollectionCopyMethod(cls, "ToDtos", "ToDto", entityClassName, dtoClassName);
      ConverterCollectionWithRelatedCopyMethod(cls, "ToDtosWithRelated", "ToDtoWithRelated", entityClassName, dtoClassName);
      ConverterCollectionCopyMethod(cls, "ToEntities", "ToEntity", dtoClassName, entityClassName);
#>

        static partial void OnDtoCreating(<#= entityClassName #> source, <#= dtoClassName #> target);

        static partial void OnEntityCreating(<#= dtoClassName #> source, <#= entityClassName #> target);

    }
<#
      if (FilePerClass) {
#>

}
<#
        output.PopOutputRedirection();
      }
    
    } // End of converter generation

    foreach (BaseClass cls in this.NewDtosWithComplexPk) {
      string converterClassName = ConverterClassNamePrefix + cls.Name + "Key" + ConverterClassNameSuffix;
      string dtoClassName = GetDtoKeyClassName(cls);
      string rootFileName = converterClassName;

      if (FilePerClass) {
        output.Extension = ".cs";
        output.PushOutputRedirection(ConvertersOutput, rootFileName);
        GenerateConverterFileHeader();
#>

namespace <#= dtosNamespace #>
{
<#
      }
#>

    public static partial class <#= codeProvider.GetValidIdentifier(converterClassName) #>
    {
<#
      string entityClassName = GetCodeElementReference(cls);
      List<Property> idProperties = this.GetKeyProperties(cls);
      List<RelationProperty> relationProperties = new List<RelationProperty>();

      ConverterSingleObjectCopyMethod(idProperties, relationProperties, "ToDtoKey", entityClassName, dtoClassName, null);
      ConverterCollectionCopyMethod(cls, "ToDtoKeys", "ToDtoKey", entityClassName, dtoClassName);
#>
    }
<#
      if (FilePerClass) {
#>

}
<#
        output.PopOutputRedirection();
      }
    } // End of DTO key converter class generation

    if (!FilePerClass) {
#>

}
<#
      output.PopOutputRedirection();
    }

  } // End of converters generation

// End of generation
#>
<#+
  private string baseFileName = string.Empty;

  private List<BaseClass> ExistingDtosWithComplexPk = new List<BaseClass>();
  private List<BaseClass> NewDtosWithComplexPk = new List<BaseClass>();

  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// File header warning generation for automatically rewritable files.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateFileHeaderWarning() {

#>
//------------------------------------------------------------------------------
// This is auto-generated code.
//------------------------------------------------------------------------------
// This code was generated by Devart Entity Developer tool using Data Transfer Object template.
// <#= String.IsNullOrEmpty(HeaderTimestampVersionControlTag) ? "Code is generated on: " + DateTime.Now : HeaderTimestampVersionControlTag #>
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//------------------------------------------------------------------------------

<#+

  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// DTO class file header generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateDtoFileHeader() {

    GenerateFileHeaderWarning();

#>
using System.Collections.Generic;
<#+

    if (WcfDataContractAttributes) {
#>
using System.Runtime.Serialization;
<#+
    }
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Constructor generation for entity classes or complex types.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateAllDtoConstructors(BaseClass cls, string className, List<Property> properties, List<RelationProperty> relationProperties) {

    if (!GenerateDtoConstructors)
      return;

#>
        #region Constructors
  
        public <#= className #>() {
        }

        public <#= className #>(<#+

    string comma = string.Empty;

    foreach (Property prop in properties) {
      #><#= comma #><#= GetPropertyDtoType(prop) #> <#= GetVariableName(prop.Name) #><#+
      comma = ", ";
    }

    foreach (RelationProperty rp in relationProperties) {
      #><#= comma #><#= GetRelationPropertyDtoType(rp) #> <#= GetVariableName(rp.Name) #><#+
      comma = ", ";
    }

#>) {

<#+

    foreach (Property prop in properties) {
#>          this.<#= codeProvider.GetValidIdentifier(prop.Name) #> = <#= GetVariableName(prop.Name) #>;
<#+
    }

    foreach (RelationProperty rp in relationProperties) {
#>          this.<#= codeProvider.GetValidIdentifier(rp.Name) #> = <#= GetVariableName(rp.Name) #>;
<#+
    }
#>
        }

        #endregion
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// All properties generation for entity classes or complex types.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateAllProperties(List<Property> allProperties) {

    if (allProperties.Count == 0)
      return;
#>

        #region Properties
<#+

    foreach (Property property in allProperties)
      GenerateProperty(property);

#>

        #endregion
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Property generation for entity classes or complex types.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateProperty(Property property) {

#>

<#+
    string currentPropertyType = GetPropertyDtoType(property);

    GenerateWcfDataMemberAttributeIfNeeded();
#>
        public <#= currentPropertyType #> <#= codeProvider.GetValidIdentifier(property.Name) #> { get; set; }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get DTO equivalent type for property type.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private string GetPropertyDtoType(Property property) {

    if (property.Type is ICodeElement) {
      if (property.IsComplexType) {
        ComplexType complexType = (ComplexType)property.Type;
        return DtoClassNamePrefix + complexType.Name + DtoClassNameSuffix;
      }
      else {
        string propertyType = codeProvider.GetNullableType(property.Nullable, GetCodeElementReference((ICodeElement)property.Type));
   	    if (property.IsEnumType && property.Nullable)
          propertyType = codeProvider.FormatNullable(propertyType);
        return propertyType;
      }
    }
    else
      return codeProvider.GetNullableType(property.Nullable, property.Type);
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// All generatable properties.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private List<Property> GetActiveProperties(BaseClass cls) {

    ICollection<Property> allProperties;

    Class realClass = cls as Class;
    if (realClass != null)
      allProperties = realClass.AllProperties;
    else
      allProperties = cls.Properties;

    var activeProperties = allProperties
      .Where(prop => (bool)prop.GetProperty("GenerateDTO") &&
                     (!prop.IsComplexType || (bool)((ComplexType)prop.Type).GetProperty("GenerateDTO")))
      .ToList();

    return activeProperties;
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// All relation properties generation for entity classes.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateAllRelationProperties(List<RelationProperty> relationProperties) {

    if (relationProperties.Count == 0)
      return;
#>

        #region Navigation Properties
<#+

    foreach (RelationProperty relationProperty in relationProperties)
      GenerateRelationProperty(relationProperty);

#>

        #endregion
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Relation property generation for entity classes.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateRelationProperty(RelationProperty relationProperty) {

#>

<#+ 
    string currentPropertyType = GetRelationPropertyDtoType(relationProperty);

    GenerateRelationWcfDataContractAttributes(relationProperty);
#>
        public <#= currentPropertyType #> <#= codeProvider.GetValidIdentifier(relationProperty.Name) #> { get; set; }
<#+ 

  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get DTO equivalent type for relation property type.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private string GetRelationPropertyDtoType(RelationProperty relationProperty) {

    string currentPropertyType;
    if (UseDtoClassesInAssociations)
      currentPropertyType = GetDtoClassName(relationProperty.RelationClass);
    else
      if (this.ExistingDtosWithComplexPk.Contains(relationProperty.RelationClass))
        currentPropertyType = GetDtoClassName(relationProperty.RelationClass);
      else
        if (this.NewDtosWithComplexPk.Contains(relationProperty.RelationClass))
          currentPropertyType = GetDtoKeyClassName(relationProperty.RelationClass);
        else {
          Property prop = GetOtherKeyProperties(relationProperty).Single();
          currentPropertyType = GetPropertyDtoType(prop);
        }

    if (relationProperty.Multiplicity == Multiplicity.Many)
      currentPropertyType = "List<" + currentPropertyType + ">";

    return currentPropertyType;
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get other key properties for relation property.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private List<Property> GetOtherKeyProperties(RelationProperty relationProperty) {

    return GetKeyProperties(relationProperty.RelationClass);
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get key properties for class.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private List<Property> GetKeyProperties(BaseClass cls) {

    return cls.Properties
      .Where(prop => prop.PrimaryKey)
      .ToList();
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// All generatable relation properties.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private List<RelationProperty> GetActiveRelationProperties(BaseClass baseClass) {

    Class cls = baseClass as Class;

    if (cls == null)
      return new List<RelationProperty>();
    var relationProperties = cls.RelationProperties
      .Where(rp => rp.Generate &&
                   (bool)rp.GetProperty("GenerateDTO") &&
                   (bool)rp.Association.GetProperty("GenerateDTO")).ToList();
     
     while(cls.BaseClass != null) {
      cls = cls.BaseClass;
      relationProperties.AddRange(cls.RelationProperties
      .Where(rp => rp.Generate &&
                   (bool)rp.GetProperty("GenerateDTO") &&
                   (bool)rp.Association.GetProperty("GenerateDTO")));
    }

    if (UseDtoClassesInAssociations) {
      return relationProperties
        .Where(rp => (bool)rp.RelationClass.GetProperty("GenerateDTO"))
        .ToList();
    }
    else {
      List<RelationProperty> activeRelations = new List<RelationProperty>();
      foreach (RelationProperty rp in relationProperties) {
        if (rp.Multiplicity == Multiplicity.Many) {
          var otherKeyProperties = GetOtherKeyProperties(rp);          
          if (otherKeyProperties.Count == 0) {
            if ((bool)rp.RelationClass.GetProperty("GenerateDTO")) {
              activeRelations.Add(rp);
              if (!this.ExistingDtosWithComplexPk.Contains(rp.RelationClass))
                this.ExistingDtosWithComplexPk.Add(rp.RelationClass);
            }
          }
          else {
            activeRelations.Add(rp);
            if (otherKeyProperties.Count > 1)
              if (!this.NewDtosWithComplexPk.Contains(rp.RelationClass))
                this.NewDtosWithComplexPk.Add(rp.RelationClass);
          }
        }
      }
      return activeRelations;
    }
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get DTO class name.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private string GetDtoClassName(BaseClass cls) {

    return DtoClassNamePrefix + cls.Name + DtoClassNameSuffix;
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Get DTO key class name.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private string GetDtoKeyClassName(BaseClass cls) {

    return DtoClassNamePrefix + cls.Name + "Key" + DtoClassNameSuffix;
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// WCF Data Contract DataContract attribute generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateWcfDataContractAttributeIfNeeded() {

    if (WcfDataContractAttributes) {
#>
    [DataContractAttribute(IsReference=true)]
<#+
    }
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// WCF Data Contract DataMember attribute generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateWcfDataMemberAttributeIfNeeded() {

    if (WcfDataContractAttributes) {
#>
        [DataMember]
<#+
    }
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  //
  // Method GenerateRelationWcfDataContractAttributes()
  // WCF Data Contract attributes generation for relation property.
  //
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateRelationWcfDataContractAttributes(RelationProperty relationProperty) {

    if (WcfDataContractAttributes) {
        if (relationProperty.Multiplicity == Multiplicity.Many && 
            (WcfDataMemberOnNavigationProperties == WcfDataMemberGenerationBehavior.ManyEnd ||
            WcfDataMemberOnNavigationProperties == WcfDataMemberGenerationBehavior.All) ||
            relationProperty.Multiplicity != Multiplicity.Many && 
            (WcfDataMemberOnNavigationProperties == WcfDataMemberGenerationBehavior.OneEnd ||
            WcfDataMemberOnNavigationProperties == WcfDataMemberGenerationBehavior.All)) {
#>
        [DataMember]
<#+
        }
	}
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter file header generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void GenerateConverterFileHeader() {

    GenerateFileHeaderWarning();
#>
using System.Collections.Generic;
using System.Linq;
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter copying method code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterSingleObjectCopyMethod(List<Property> allProperties, List<RelationProperty> relationProperties, string singleObjectConvertionMethod, string sourceClassName, string targetClassName, string onMethodName) {
#>

        public static <#= targetClassName #> <#= singleObjectConvertionMethod #>(this <#= sourceClassName #> source)
        {
            if (source == null)
              return null;

            var target = new <#= targetClassName #>();
<#+
      ConverterCopyProperties(allProperties, singleObjectConvertionMethod);

      if (!string.IsNullOrEmpty(onMethodName)) {
#>

            // User-defined partial method
            <#= onMethodName #>(source, target);
<#+
      }
#>

            return target;
        }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter properties copying code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterCopyProperties(List<Property> allProperties, string complexTypeConvertionMethod) {

    if (allProperties.Count == 0)
      return;
#>

            // Properties
<#+

    foreach (Property prop in allProperties) {
      string propertyName = codeProvider.GetValidIdentifier(prop.Name);
#>
            target.<#= propertyName #> = source.<#= propertyName #><#= prop.IsComplexType ? "." + complexTypeConvertionMethod + "()" : string.Empty #>;
<#+
    }
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter copying method code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterSingleObjectWithRelatedCopyMethod(List<Property> allProperties, List<RelationProperty> relationProperties, string complexTypeConvertionMethod, string singleObjectConvertionMethod, string collectionConvertionMethod, string sourceClassName, string targetClassName, string onMethodName) {
#>

        public static <#= targetClassName #> <#= singleObjectConvertionMethod #>(this <#= sourceClassName #> source, int level)
        {
            if (source == null)
              return null;

            var target = new <#= targetClassName #>();
<#+
      ConverterCopyProperties(allProperties, complexTypeConvertionMethod);
      ConverterCopyRelationProperties(relationProperties, singleObjectConvertionMethod, collectionConvertionMethod);

      if (!string.IsNullOrEmpty(onMethodName)) {
#>

            // User-defined partial method
            <#= onMethodName #>(source, target);
<#+
      }
#>

            return target;
        }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter navigation properties copying code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterCopyRelationProperties(List<RelationProperty> relationProperties, string singleObjectConvertionMethod, string collectionConvertionMethod) {

    if (relationProperties.Count == 0)
      return;
#>

            // Navigation Properties
            if (level > 0) {
<#+

    foreach (RelationProperty rp in relationProperties) {
      string propertyName = codeProvider.GetValidIdentifier(rp.Name);
#>
              target.<#= propertyName #> = source.<#= propertyName #><#+

      if (UseDtoClassesInAssociations || this.ExistingDtosWithComplexPk.Contains(rp.RelationClass)) {
        string convertionMethod = rp.Multiplicity == Multiplicity.Many ? collectionConvertionMethod : singleObjectConvertionMethod;
        #>.<#= convertionMethod #>(level - 1);
<#+
      }
      else {
        if (!this.NewDtosWithComplexPk.Contains(rp.RelationClass)) {
          Property idProperty = GetOtherKeyProperties(rp).Single();
          string idPropertyName = codeProvider.GetValidIdentifier(idProperty.Name);
          #>

                  .Select(src => src.<#= idPropertyName #>)
                  .ToList();
<#+
        }
        else {
          string convertionMethod = rp.Multiplicity == Multiplicity.Many ? "ToDtoKeys" : "ToDtoKey";
          #>.<#= convertionMethod #>();
<#+
        }
      }
    }
#>
            }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter copying method code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterCollectionCopyMethod(BaseClass cls, string methodName, string singleMethodName, string sourceClassName, string targetClassName) {
#>

        public static List<<#= targetClassName #>> <#= methodName #>(this IEnumerable<<#= sourceClassName #>> source)
        {
            if (source == null)
              return null;

            var target = source
              .Select(src => src.<#= singleMethodName #>())
              .ToList();

            return target;
        }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  /// <summary>
  /// Converter copying method code generation.
  /// </summary>
  //////////////////////////////////////////////////////////////////////////////////
  private void ConverterCollectionWithRelatedCopyMethod(BaseClass cls, string methodName, string singleMethodName, string sourceClassName, string targetClassName) {
#>

        public static List<<#= targetClassName #>> <#= methodName #>(this IEnumerable<<#= sourceClassName #>> source, int level)
        {
            if (source == null)
              return null;

            var target = source
              .Select(src => src.<#= singleMethodName #>(level))
              .ToList();

            return target;
        }
<#+
  }
#>
<#+
  //////////////////////////////////////////////////////////////////////////////////
  //
  // Utility methods
  //
  //////////////////////////////////////////////////////////////////////////////////

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

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

    if (!string.IsNullOrEmpty(DtoNamespace))
      return codeProvider.GetValidIdentifier(model.GetDefaultNamespace()) + "." + codeProvider.GetValidIdentifier(element.Name);

    return codeProvider.GetValidIdentifier(element.Name);
  }

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

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

Post Reply