Advertisement
nathanaw

EF Iterator.tt that avoids StackOverflowException issues

Aug 26th, 2011
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.01 KB | None | 0 0
  1. <#@ template language="C#" debug="false" hostspecific="true"#>
  2. <#@ include file="EF.Utility.CS.ttinclude"#>
  3. <#@ output extension=".cs"#><#
  4. // Copyright (c) Microsoft Corporation.  All rights reserved.
  5.  
  6. CodeGenerationTools code = new CodeGenerationTools(this);
  7. MetadataTools ef = new MetadataTools(this);
  8. MetadataLoader loader = new MetadataLoader(this);
  9. CodeRegion region = new CodeRegion(this);
  10.  
  11. string inputFile = @"Entities.edmx";
  12. EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
  13. string namespaceName = code.VsNamespaceSuggestion();
  14.  
  15. EntityContainer container = ItemCollection.GetItems<EntityContainer>().FirstOrDefault();
  16. if (container == null)
  17. {
  18.     return "// No EntityContainer exists in the model, so no code was generated";
  19. }
  20. #>
  21. //------------------------------------------------------------------------------
  22. // <auto-generated>
  23. //     This code was generated from a template.
  24. //
  25. //     Changes to this file may cause incorrect behavior and will be lost if
  26. //     the code is regenerated.
  27. // </auto-generated>
  28. //------------------------------------------------------------------------------
  29.  
  30. using System;
  31. using System.Collections.Generic;
  32. using System.Collections.ObjectModel;
  33. using System.Linq;
  34. using System.Runtime.Serialization;
  35.  
  36. <#
  37. if (!String.IsNullOrEmpty(namespaceName))
  38. {
  39. #>
  40. namespace <#=code.EscapeNamespace(namespaceName)#>
  41. {
  42. <#
  43.     PushIndent(CodeRegion.GetIndent(1));
  44. }
  45. #>
  46. [DataContract(IsReference = true)]
  47. <#
  48. foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
  49. {
  50. #>
  51. [KnownType(typeof(<#=code.Escape(entity)#>))]
  52. <#
  53. }
  54. #>
  55. <#=Accessibility.ForType(container)#> class <#=code.Escape(container)#>Iterator : IEnumerable<object>
  56. {
  57.     [DataMember(Name = "Items")]
  58.     private List<object> _items;
  59.  
  60.     private List<object> _leafsToExploreFurther = new List<object>();
  61.  
  62.     #region Constructors
  63.  
  64.     private <#=code.Escape(container)#>Iterator()
  65.     {
  66.     }
  67.  
  68.     #endregion
  69.  
  70.     #region Factory Methods
  71.  
  72.     public static <#=code.Escape(container)#>Iterator Create<T>(T entity)
  73.     {
  74.         <#=code.Escape(container)#>Iterator iterator = new <#=code.Escape(container)#>Iterator();
  75.         iterator.Visit(entity, 0);
  76.  
  77.         while (iterator._leafsToExploreFurther.Count > 0)
  78.         {
  79.             var leaf = iterator._leafsToExploreFurther[0];
  80.             iterator._leafsToExploreFurther.Remove(leaf);
  81.             iterator.Visit(leaf, 0);
  82.         }
  83.  
  84.         return iterator;
  85.     }
  86.  
  87.     #endregion
  88.  
  89.     #region Execute Methods
  90.  
  91.     public void Execute<TFilter>(Action<TFilter> action)
  92.     {
  93.         foreach (var item in Items.OfType<TFilter>())
  94.         {
  95.             action(item);
  96.         }
  97.     }
  98.  
  99.     public static void Execute<TFilter>(<#=code.Escape(container)#>Iterator iterator, Action<TFilter> action)
  100.     {
  101.         foreach (var item in iterator.Items.OfType<TFilter>())
  102.         {
  103.             action(item);
  104.         }
  105.     }
  106.  
  107.     public static void Execute<TEntity, TFilter>(TEntity entity, Action<TFilter> action)
  108.     {
  109.         <#=code.Escape(container)#>Iterator iterator = <#=code.Escape(container)#>Iterator.Create(entity);
  110.         foreach (var item in iterator.Items.OfType<TFilter>())
  111.         {
  112.             action(item);
  113.         }
  114.     }
  115.  
  116.     #endregion
  117.  
  118.     #region Properties
  119.  
  120.     public ReadOnlyCollection<object> Items
  121.     {
  122.         get
  123.         {
  124.             return WritableItems.AsReadOnly();
  125.         }
  126.     }
  127.  
  128.     protected List<object> WritableItems
  129.     {
  130.         get
  131.         {
  132.             if (_items == null)
  133.             {
  134.                 _items = new List<object>();
  135.             }
  136.             return _items;
  137.         }
  138.     }
  139.  
  140.     #endregion
  141.  
  142.     #region Visit Method
  143.  
  144.     internal void Visit(dynamic entity, int depth)
  145.     {
  146.         // Prevent stack overflows by tracking the call depth.
  147.         // If over a certain value, then store that leaf node for further exploration in a later loop.
  148.         if (depth >= 20)
  149.         {
  150.             _leafsToExploreFurther.Add(entity);
  151.             return;
  152.         }
  153.  
  154.         if (entity != null && !WritableItems.Contains(entity))
  155.         {
  156.             WritableItems.Add(entity);
  157.             <#=code.Escape(container)#>Extensions.Traverse(entity, this, depth + 1);
  158.         }
  159.     }
  160.  
  161.     #endregion
  162.  
  163.     #region IEnumerable Implementation
  164.  
  165.     IEnumerator<object> IEnumerable<object>.GetEnumerator()
  166.     {
  167.         return Items.GetEnumerator();
  168.     }
  169.  
  170.     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  171.     {
  172.         return Items.GetEnumerator();
  173.     }
  174.  
  175.     #endregion
  176. }
  177.  
  178. <#=Accessibility.ForType(container)#> static partial class <#=code.Escape(container)#>Extensions
  179. {
  180.     #region Traverse Methods
  181.  
  182. <#
  183. foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
  184. {
  185. #>
  186.     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "entity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "visitor")]
  187.     internal static void Traverse(this <#=code.Escape(entity)#> entity, <#=code.Escape(container)#>Iterator visitor, int depth)
  188.     {
  189. <#
  190.     if (entity.BaseType != null)
  191.     {
  192. #>
  193.         Traverse((<#=code.Escape(entity.BaseType)#>)entity, visitor, depth + 1);
  194. <#
  195.     }
  196. #>
  197. <#
  198.     foreach (var navProperty in entity.NavigationProperties.Where(np => np.DeclaringType == entity))
  199.     {
  200.         if(navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
  201.         {
  202. #>
  203.         if (entity.<#=code.Escape(navProperty)#> != null)
  204.         {
  205.             foreach (var value in entity.<#=code.Escape(navProperty)#>)
  206.             {
  207.                 visitor.Visit(value, depth + 1);
  208.             }
  209.         }
  210. <#
  211.         }
  212.         else
  213.         {
  214. #>
  215.         if (entity.<#=code.Escape(navProperty)#> != null)
  216.         {
  217.             visitor.Visit(entity.<#=code.Escape(navProperty)#>, depth + 1);
  218.         }
  219. <#
  220.         }
  221.     }
  222. #>
  223.     }
  224.  
  225. <#
  226. }
  227. #>
  228.     #endregion
  229. }
  230.  
  231. <#
  232. if (!String.IsNullOrEmpty(namespaceName))
  233. {
  234.     PopIndent();
  235. #>
  236. }
  237. <#
  238. }
  239. #>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement