fork download
  1. <#
  2. // You can use this text template to customize object layer code generation for
  3. // applications that use the Entity Framework. The template generates code based on an .edmx file.
  4. // Before using this template, note the following:
  5. //
  6. // *The name of the text template file will determine the name of the code file it generates.
  7. // For example, if the text template is named TextTemplate.tt, the generated file will be named
  8. // TextTemplate.vb or TextTemplate.cs.
  9. // *The Custom Tool property of the targeted .edmx file must be empty. For more information,
  10. // see .edmx File Properties (http://go.microsoft.com/fwlink/?LinkId=139299).
  11. // *The SourceCsdlPath initialization below must be set to one of the following:
  12. // 1) the path of the targeted .edmx or .csdl file
  13. // 2) the path of the targeted .edmx or .csdl file relative to the template path
  14. //
  15. // For more detailed information about using this template, see
  16. // How to: Customize Object Layer Code Generation (http://go.microsoft.com/fwlink/?LinkId=139297).
  17. // For general information about text templates, see
  18. // Generating Artifacts by Using Text Templates (http://go.microsoft.com/fwlink/?LinkId=139298)
  19. #>
  20. <#@ template language="C#" debug="false" hostspecific="true"#>
  21. <#@ include file="EF.Utility.CS.ttinclude"#><#@
  22. output extension=".cs"#><#
  23.  
  24. var sharedNamespace="Project.Shared";
  25. var behaviorNamespace=sharedNamespace+".Behaviors";
  26. var dtoNamespace=sharedNamespace+".DataInterfaces";
  27. ///http://d...content-available-to-author-only...s.com/2010/01/28/tracing-sql-statements-generated-by-entity-framework/
  28. var generateTracer=true;
  29.  
  30. UserSettings userSettings =
  31. new UserSettings
  32. {
  33. SourceCsdlPath = @"..\Project\DbModel.edmx",
  34. ReferenceCsdlPaths = new string[] {},
  35. FullyQualifySystemTypes = true,
  36. CreateContextAddToMethods = true,
  37. CamelCaseFields = false,
  38. };
  39.  
  40. ApplyUserSettings(userSettings);
  41. if(Errors.HasErrors)
  42. {
  43. return String.Empty;
  44. }
  45.  
  46. MetadataLoader loader = new MetadataLoader(this);
  47. MetadataTools ef = new MetadataTools(this);
  48. CodeRegion region = new CodeRegion(this);
  49. CodeGenerationTools code = new CodeGenerationTools(this){FullyQualifySystemTypes = userSettings.FullyQualifySystemTypes, CamelCaseFields = userSettings.CamelCaseFields};
  50.  
  51. ItemCollection = loader.CreateEdmItemCollection(SourceCsdlPath, ReferenceCsdlPaths.ToArray());
  52. ModelNamespace = loader.GetModelNamespace(SourceCsdlPath);
  53. string namespaceName = code.VsNamespaceSuggestion();
  54. UpdateObjectNamespaceMap(namespaceName);
  55.  
  56. #>
  57. //------------------------------------------------------------------------------
  58. // <auto-generated>
  59. // <#=GetResourceString("Template_GeneratedCodeCommentLine1")#>
  60. //
  61. // <#=GetResourceString("Template_GeneratedCodeCommentLine2")#>
  62. // <#=GetResourceString("Template_GeneratedCodeCommentLine3")#>
  63. // </auto-generated>
  64. //------------------------------------------------------------------------------
  65.  
  66. using System;
  67. using System.Collections.Generic;
  68. using System.ComponentModel;
  69. using System.ComponentModel.DataAnnotations;
  70. using System.Linq;
  71. using System.Linq.Expressions;
  72. using System.Xml.Serialization;
  73. using System.Runtime.Serialization;
  74.  
  75. using <#=dtoNamespace#>;
  76.  
  77. <#
  78. if (!String.IsNullOrEmpty(namespaceName))
  79. {
  80. #>
  81.  
  82. namespace <#=namespaceName#>
  83. {
  84. <#
  85. PushIndent(CodeRegion.GetIndent(1));
  86. }
  87.  
  88. ////////
  89. //////// Write EntityContainer and ObjectContext classes.
  90. ////////
  91.  
  92. region.Begin(GetResourceString("Template_RegionContexts"));
  93. foreach (EntityContainer container in GetSourceSchemaTypes<EntityContainer>())
  94. {
  95. #>
  96.  
  97. /// <summary>
  98. /// <#=SummaryComment(container)#>
  99. /// </summary><#=LongDescriptionCommentElement(container, region.CurrentIndentLevel)#>
  100. <#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#>: <# { bool first=true; #>
  101.  
  102. <# foreach(string entity in GetSourceSchemaTypes<EntityType>().OrderBy(e => e.Name).Select(e=>behaviorNamespace+".IRepository<I"+code.Escape(e)+">"))
  103. {#>
  104. <# if(first){first=false;} else{ Write(",");}#><#=entity#>
  105. <# } }#>
  106.  
  107. {
  108. #region <#=GetResourceString("Template_RegionConstructors")#>
  109.  
  110. /// <summary>
  111. /// <#=String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_ContextDefaultCtorComment"), container.Name, container.Name)#>
  112. /// </summary>
  113. public <#=code.Escape(container)#>()
  114. {
  115. OnContextCreated();
  116. }
  117.  
  118. /// <summary>
  119. /// <#=String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_ContextCommonCtorComment"), container.Name)#>
  120. /// </summary>
  121. public <#=code.Escape(container)#>(string connectionString)
  122. {
  123. OnContextCreated();
  124. }
  125.  
  126. /// <summary>
  127. /// <#=String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_ContextCommonCtorComment"), container.Name)#>
  128. /// </summary>
  129. public <#=code.Escape(container)#>(object connection)
  130. {
  131. OnContextCreated();
  132. }
  133.  
  134. #endregion <#=GetResourceString("Template_RegionConstructors")#>
  135.  
  136. #region <#=GetResourceString("Template_RegionPartialMethods")#>
  137.  
  138. partial void OnContextCreated();
  139.  
  140. #endregion <#=GetResourceString("Template_RegionPartialMethods")#>
  141.  
  142. <#
  143. ////////
  144. //////// Write EntityContainer and ObjectContext ObjectSet properties.
  145. ////////
  146. region.Begin(GetResourceString("Template_RegionObjectSetProperties"));
  147. foreach (EntitySet set in container.BaseEntitySets.OfType<EntitySet>())
  148. {
  149. VerifyEntityTypeAndSetAccessibilityCompatability(set);
  150. #>
  151.  
  152. /// <summary>
  153. /// <#=SummaryComment(set)#>
  154. /// </summary><#=LongDescriptionCommentElement(set, region.CurrentIndentLevel)#>
  155. <#=code.SpaceAfter(NewModifier(set))#><#=Accessibility.ForReadOnlyProperty(set)#> IList<<#=MultiSchemaEscape(set.ElementType, code)#>> <#=code.Escape(set)#>
  156. {
  157. get
  158. {
  159. if ((<#=code.FieldName(set)#> == null))
  160. {
  161. <#=code.FieldName(set)#> = new List<<#=MultiSchemaEscape(set.ElementType, code)#>>();
  162. }
  163. return <#=code.FieldName(set)#>;
  164. }
  165. }
  166. IList<<#=MultiSchemaEscape(set.ElementType, code)#>> <#=code.FieldName(set)#>;
  167. <#
  168. }
  169. region.End(); //Object Set properties region
  170.  
  171.  
  172.  
  173. ////////
  174. //////// Write AddTo<EntitySet> methods.
  175. ////////
  176. //////// Set the CreateContextAddToMethods property of the UserSettings object to false
  177. //////// to turn off generation of the AddTo methods.
  178. ////////
  179. region.Begin(GetResourceString("Template_RegionAddToMethods"));
  180. IEnumerable<EntitySet> addToMethods = CreateContextAddToMethods.Value ? container.BaseEntitySets.OfType<EntitySet>() : Enumerable.Empty<EntitySet>();
  181. foreach (EntitySet set in addToMethods)
  182. {
  183. string parameterName = code.Escape(FixParameterName(set.ElementType.Name, code));
  184. #>
  185.  
  186. /// <summary>
  187. /// <#=String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_GenCommentAddToMethodCs"), set.Name)#>
  188. /// </summary>
  189. <#=Accessibility.ForType(set.ElementType)#> void AddTo<#=set.Name#>(<#=MultiSchemaEscape(set.ElementType, code)#> <#=parameterName#>)
  190. {
  191. <#=set.Name#>.Add(<#=parameterName#>);
  192. }
  193. <#
  194. }
  195. region.End();
  196. WriteLine("//#endregion"+ GetResourceString("Template_RegionAddToMethods"));
  197.  
  198. ////////
  199. //////// Write EntityContainer and ObjectContext Function Import methods.
  200. ////////
  201. region.Begin(GetResourceString("Template_RegionFunctionImports"));
  202. foreach (EdmFunction edmFunction in container.FunctionImports)
  203. {
  204.  
  205. IEnumerable<FunctionImportParameter> parameters = FunctionImportParameter.Create(edmFunction.Parameters, code, ef);
  206. string paramList = string.Join(", ", parameters.Select(p => p.FunctionParameterType + " " + p.FunctionParameterName).ToArray());
  207. TypeUsage returnType = edmFunction.ReturnParameter == null ? null : ef.GetElementType(edmFunction.ReturnParameter.TypeUsage);
  208. #>
  209.  
  210. /// <summary>
  211. /// <#=SummaryComment(edmFunction)#>
  212. /// </summary><#=LongDescriptionCommentElement(edmFunction, region.CurrentIndentLevel)#><#=ParameterComments(parameters.Select(p => new Tuple<string, string>(p.RawFunctionParameterName, SummaryComment(p.Source))), region.CurrentIndentLevel)#>
  213. <#=code.SpaceAfter(NewModifier(edmFunction))#><#=Accessibility.ForMethod(edmFunction)#> <#=returnType == null ? "int" : "ObjectResult<" + MultiSchemaEscape(returnType, code) + ">"#> <#=code.Escape(edmFunction)#>(<#=paramList#>)
  214. {
  215. <#
  216. foreach (FunctionImportParameter parameter in parameters)
  217. {
  218. if (!parameter.NeedsLocalVariable)
  219. continue;
  220. #>
  221. ObjectParameter <#=parameter.LocalVariableName#>;
  222. if (<#=parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"#>)
  223. {
  224. <#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", <#=parameter.FunctionParameterName#>);
  225. }
  226. else
  227. {
  228. <#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", typeof(<#=parameter.RawClrTypeName#>));
  229. }
  230.  
  231. <#
  232. }
  233. #>
  234. return base.ExecuteFunction<#=returnType == null ? "" : "<" + MultiSchemaEscape(returnType, code) + ">"#>("<#=edmFunction.Name#>"<#=code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))#>);
  235. }
  236. <#
  237. if(returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
  238. {
  239. #>
  240. /// <summary>
  241. /// <#=SummaryComment(edmFunction)#>
  242. /// </summary><#=LongDescriptionCommentElement(edmFunction, region.CurrentIndentLevel)#>
  243. /// <param name="mergeOption"></param><#=ParameterComments(parameters.Select(p => new Tuple<string, string>(p.RawFunctionParameterName, SummaryComment(p.Source))), region.CurrentIndentLevel)#>
  244. <#=code.SpaceAfter(NewModifier(edmFunction))#><#=Accessibility.ForMethod(edmFunction)#> <#=returnType == null ? "int" : "ObjectResult<" + MultiSchemaEscape(returnType, code) + ">"#> <#=code.Escape(edmFunction)#>(<#=code.StringAfter(paramList, ", ")#>MergeOption mergeOption)
  245. {
  246. <#
  247. foreach (FunctionImportParameter parameter in parameters)
  248. {
  249. if (!parameter.NeedsLocalVariable)
  250. continue;
  251. #>
  252. ObjectParameter <#=parameter.LocalVariableName#>;
  253. if (<#=parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"#>)
  254. {
  255. <#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", <#=parameter.FunctionParameterName#>);
  256. }
  257. else
  258. {
  259. <#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", typeof(<#=parameter.RawClrTypeName#>));
  260. }
  261.  
  262. <#
  263. }
  264. #>
  265. return base.<#=returnType == null ? "ExecuteFunction" : "ExecuteFunction<" + MultiSchemaEscape(returnType, code) + ">"#>("<#=edmFunction.Name#>", mergeOption<#=code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))#>);
  266. }
  267. <#
  268. }
  269. }
  270. region.End();
  271. #> #region IRepositories
  272.  
  273. //foreach (EntitySet set in container.BaseEntitySets.OfType<EntitySet>())
  274. <# foreach (EntitySet set in container.BaseEntitySets.OfType<EntitySet>().OrderBy(e => e.Name))
  275. {
  276. #>
  277. /// <summary>
  278. /// Class to enable business logic to query a source without knowing implementation of the source
  279. /// </summary>
  280. IQueryable<I<#=MultiSchemaEscape(set.ElementType, code)#>> <#=behaviorNamespace#>.IRepository<I<#=MultiSchemaEscape(set.ElementType, code)#>>.GetAll()
  281. {
  282. return this.<#=code.Escape(set)#>.Cast<I<#=MultiSchemaEscape(set.ElementType, code)#>>().AsQueryable();
  283. }
  284.  
  285. IQueryable<I<#=MultiSchemaEscape(set.ElementType, code)#>> <#=behaviorNamespace#>.IRepository<I<#=MultiSchemaEscape(set.ElementType, code)#>>.Find(Expression<Func<I<#=MultiSchemaEscape(set.ElementType, code)#>,bool>> predicate)
  286. {
  287. return this.<#=code.Escape(set)#>.Cast<I<#=MultiSchemaEscape(set.ElementType, code)#>>().AsQueryable().Where(predicate);
  288. }
  289. <#}#>
  290. #endregion IRepositories
  291.  
  292. }
  293.  
  294. <#
  295. }
  296. region.End();
  297. #>
  298.  
  299. <#
  300. ////////
  301. //////// Write EntityType classes.
  302. ////////
  303. region.Begin(GetResourceString("Template_RegionEntities"));
  304. #>
  305.  
  306. public class MemoryModel:INotifyPropertyChanged,INotifyPropertyChanging {
  307. public event PropertyChangedEventHandler PropertyChanged;
  308. public event PropertyChangingEventHandler PropertyChanging;
  309. protected void ReportPropertyChanging(string property)
  310. {
  311. if(PropertyChanging!=null)
  312. PropertyChanging(this,new PropertyChangingEventArgs( property));
  313. }
  314. protected void ReportPropertyChanged(string property)
  315. {
  316. if(PropertyChanged!=null)
  317. PropertyChanged(this,new PropertyChangedEventArgs( property));
  318. }
  319. }
  320. <#
  321. foreach (EntityType entity in GetSourceSchemaTypes<EntityType>().OrderBy(e => e.Name))
  322. {
  323. #>
  324.  
  325. /// <summary>
  326. /// <#=SummaryComment(entity)#>
  327. /// </summary><#=LongDescriptionCommentElement(entity, region.CurrentIndentLevel)#>
  328. [Serializable()]
  329. [DataContract(IsReference=true)]
  330. <#
  331. foreach (EntityType subType in ItemCollection.GetItems<EntityType>().Where(b => b.BaseType == entity))
  332. {
  333. #>
  334.  
  335. [KnownTypeAttribute(typeof(<#=MultiSchemaEscape(subType, code)#>))]
  336. <#
  337. }
  338. #>
  339. <#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#>
  340. : <#=BaseTypeName(entity, code)#>,
  341. I<#=code.Escape(entity)#>,INotifyPropertyChanged,INotifyPropertyChanging
  342.  
  343. {
  344.  
  345.  
  346. <#
  347. if (!entity.Abstract)
  348. {
  349. WriteFactoryMethod(entity, code);
  350. }
  351.  
  352. region.Begin(GetResourceString("Template_RegionPrimitiveProperties"));
  353. foreach (EdmProperty property in entity.Properties.Where(p => p.DeclaringType == entity && p.TypeUsage.EdmType is PrimitiveType))
  354. {
  355. VerifyGetterAndSetterAccessibilityCompatability(property);
  356. WritePrimitiveTypeProperty(property, code);
  357. }
  358. region.End();
  359.  
  360. region.Begin(GetResourceString("Template_RegionComplexProperties"));
  361. foreach (EdmProperty property in entity.Properties.Where(p => p.DeclaringType == entity && p.TypeUsage.EdmType is ComplexType))
  362. {
  363. VerifyGetterAndSetterAccessibilityCompatability(property);
  364. WriteComplexTypeProperty(property, code);
  365. }
  366. region.End();
  367. #>
  368. }
  369. <# }
  370. region.End();
  371.  
  372. ////////
  373. //////// Write ComplexType classes.
  374. ////////
  375. region.Begin(GetResourceString("Template_RegionComplexTypes"));
  376. foreach (ComplexType complex in GetSourceSchemaTypes<ComplexType>().OrderBy(c => c.Name))
  377. {
  378. #>
  379.  
  380. /// <summary>
  381. /// <#=SummaryComment(complex)#>
  382. /// </summary><#=LongDescriptionCommentElement(complex, region.CurrentIndentLevel)#>
  383. [EdmComplexTypeAttribute(NamespaceName="<#=complex.NamespaceName#>", Name="<#=complex.Name#>")]
  384. [DataContractAttribute(IsReference=true)]
  385. [Serializable()]
  386. <#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> : ComplexObject
  387. {
  388. <#
  389. WriteFactoryMethod(complex, code);
  390. region.Begin(GetResourceString("Template_RegionPrimitiveProperties"));
  391. foreach (EdmProperty property in complex.Properties.Where(p => p.DeclaringType == complex && p.TypeUsage.EdmType is PrimitiveType))
  392. {
  393. VerifyGetterAndSetterAccessibilityCompatability(property);
  394. WritePrimitiveTypeProperty(property, code);
  395. }
  396. region.End();
  397. region.Begin(GetResourceString("Template_RegionComplexProperties"));
  398. foreach (EdmProperty property in complex.Properties.Where(p => p.DeclaringType == complex && p.TypeUsage.EdmType is ComplexType))
  399. {
  400. VerifyGetterAndSetterAccessibilityCompatability(property);
  401. WriteComplexTypeProperty(property, code);
  402. }
  403. region.End();
  404. #>
  405. }
  406. <#
  407. }
  408. region.End();
  409. #>
  410.  
  411. <#
  412. if (!String.IsNullOrEmpty(namespaceName))
  413. {
  414. PopIndent();
  415. #>
  416. }
  417. <#
  418. }
  419. VerifyTypeUniqueness();
  420. #>
  421.  
  422. <#+
  423.  
  424. ////////
  425. //////// Reusable Template Sections
  426. ////////
  427.  
  428. ////////
  429. //////// Write Factory Method.
  430. ////////
  431. private void WriteFactoryMethod(StructuralType structuralType, CodeGenerationTools code)
  432. {
  433. CodeRegion region = new CodeRegion(this, 1);
  434.  
  435. string methodName = "Create" + structuralType.Name;
  436. UniqueIdentifierService uniqueIdentifier = new UniqueIdentifierService();
  437. string instanceName = code.Escape(uniqueIdentifier.AdjustIdentifier((code.CamelCase(structuralType.Name))));
  438. IEnumerable<FactoryMethodParameter> parameters = FactoryMethodParameter.CreateParameters(structuralType.Members.OfType<EdmProperty>().Where(p => IncludePropertyInFactoryMethod(structuralType, p)), uniqueIdentifier, MultiSchemaEscape, code);
  439.  
  440. if (parameters.Count() == 0)
  441. return;
  442.  
  443. if (structuralType.Members.Any(m => m.Name == methodName))
  444. {
  445. // 6029 is the same error number that EntityClassGenerator uses for this conflict.
  446. Errors.Add(new System.CodeDom.Compiler.CompilerError(SourceCsdlPath, -1, -1, "6029",
  447. String.Format(CultureInfo.CurrentCulture,
  448. GetResourceString("Template_FactoryMethodNameConflict"), methodName, structuralType.FullName)));
  449. }
  450.  
  451. region.Begin(GetResourceString("Template_RegionFactoryMethod"));
  452. #>
  453.  
  454. /// <summary>
  455. /// <#=String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_FactoryMethodComment"), structuralType.Name)#>
  456. /// </summary><#=ParameterComments(parameters.Select(p => new Tuple<string, string>(p.RawParameterName, p.ParameterComment)), region.CurrentIndentLevel)#>
  457. public static <#=code.Escape(structuralType)#> <#=methodName#>(<#=string.Join(", ", parameters.Select(p => p.ParameterType + " " + p.ParameterName).ToArray())#>)
  458. {
  459. <#=code.Escape(structuralType)#> <#=instanceName#> = new <#=code.Escape(structuralType)#>();
  460. <#+
  461. foreach (FactoryMethodParameter parameter in parameters)
  462. {
  463. if (parameter.IsComplexType)
  464. {
  465. // ComplexType initialization.
  466. #>
  467. <#=instanceName#>.<#=code.Escape(parameter.Source)#> = StructuralObject.VerifyComplexObjectIsNotNull(<#=parameter.ParameterName#>, "<#=parameter.Source.Name#>");
  468. <#+
  469. }
  470. else
  471. {
  472. // PrimitiveType initialization.
  473. #>
  474. <#=instanceName#>.<#=code.Escape(parameter.Source)#> = <#=parameter.ParameterName#>;
  475. <#+
  476. }
  477. }
  478. #>
  479. return <#=instanceName#>;
  480. }
  481. <#+
  482. region.End();
  483. }
  484.  
  485.  
  486. ////////
  487. //////// Write PrimitiveType Properties.
  488. ////////
  489. private void WritePrimitiveTypeProperty(EdmProperty primitiveProperty, CodeGenerationTools code)
  490. {
  491. MetadataTools ef = new MetadataTools(this);
  492. #>
  493.  
  494. /// <summary>
  495. /// <#=SummaryComment(primitiveProperty)#>
  496. ///[EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)]
  497. /// </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
  498. <#= ef.IsKey(primitiveProperty)?"[Key]":string.Empty #>
  499. [DataMemberAttribute()]
  500. <#=code.SpaceAfter(NewModifier(primitiveProperty))#><#=Accessibility.ForProperty(primitiveProperty)#> <#=code.Escape(primitiveProperty.TypeUsage)#> <#=code.Escape(primitiveProperty)#>
  501. {
  502. <#=code.SpaceAfter(Accessibility.ForGetter(primitiveProperty))#>get
  503. {
  504. <#+ if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
  505. {
  506. #>
  507. return <#=code.FieldName(primitiveProperty)#>;
  508. <#+
  509. }
  510. else
  511. {
  512. #>
  513. return <#=code.FieldName(primitiveProperty)#>;
  514. <#+
  515. }
  516. #>
  517. }
  518. <#=code.SpaceAfter(Accessibility.ForSetter((primitiveProperty)))#>set
  519. {
  520. <#+
  521. if (ef.IsKey(primitiveProperty))
  522. {
  523. if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
  524. {
  525. #>
  526. if (!StructuralObject.BinaryEquals(<#=code.FieldName(primitiveProperty)#>, value))
  527. <#+
  528. }
  529. else
  530. {
  531. #>
  532. if (<#=code.FieldName(primitiveProperty)#> != value)
  533. <#+
  534. }
  535. #>
  536. {
  537. <#+
  538. PushIndent(CodeRegion.GetIndent(1));
  539. }
  540. #>
  541. <#=ChangingMethodName(primitiveProperty)#>(value);
  542. ReportPropertyChanging("<#=primitiveProperty.Name#>");
  543. <#=code.FieldName(primitiveProperty)#> =value; //StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
  544. ReportPropertyChanged("<#=primitiveProperty.Name#>");
  545. <#=ChangedMethodName(primitiveProperty)#>();
  546. <#+
  547. if (ef.IsKey(primitiveProperty))
  548. {
  549. PopIndent();
  550. #>
  551. }
  552. <#+
  553. }
  554. #>
  555. }
  556. }
  557. private <#=code.Escape(primitiveProperty.TypeUsage)#> <#=code.FieldName(primitiveProperty)#><#=code.StringBefore(" = ", code.CreateLiteral(primitiveProperty.DefaultValue))#>;
  558. partial void <#=ChangingMethodName(primitiveProperty)#>(<#=code.Escape(primitiveProperty.TypeUsage)#> value);
  559. partial void <#=ChangedMethodName(primitiveProperty)#>();
  560. <#+
  561. }
  562.  
  563. ////////
  564. //////// Write ComplexType Properties.
  565. ////////
  566. private void WriteComplexTypeProperty(EdmProperty complexProperty, CodeGenerationTools code)
  567. {
  568. #>
  569.  
  570. /// <summary>
  571. /// <#=SummaryComment(complexProperty)#>
  572. /// </summary><#=LongDescriptionCommentElement(complexProperty, 1)#>
  573. //[EdmComplexPropertyAttribute()]
  574. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  575. [XmlElement(IsNullable=true)]
  576. [SoapElement(IsNullable=true)]
  577. [DataMemberAttribute()]
  578. <#=code.SpaceAfter(NewModifier(complexProperty))#><#=Accessibility.ForProperty(complexProperty)#> <#=MultiSchemaEscape(complexProperty.TypeUsage, code)#> <#=code.Escape(complexProperty)#>
  579. {
  580. <#=code.SpaceAfter(Accessibility.ForGetter(complexProperty))#>get
  581. {
  582. <#=code.FieldName(complexProperty)#> =value; // GetValidValue(<#=code.FieldName(complexProperty)#>, "<#=complexProperty.Name#>", false, <#=InitializedTrackingField(complexProperty, code)#>);
  583. <#=InitializedTrackingField(complexProperty, code)#> = true;
  584. return <#=code.FieldName(complexProperty)#>;
  585. }
  586. <#=code.SpaceAfter(Accessibility.ForSetter(complexProperty))#>set
  587. {
  588. <#=ChangingMethodName(complexProperty)#>(value);
  589. ReportPropertyChanging("<#=complexProperty.Name#>");
  590. <#=code.FieldName(complexProperty)#> = value; //SetValidValue(<#=code.FieldName(complexProperty)#>, value, "<#=complexProperty.Name#>");
  591. <#=InitializedTrackingField(complexProperty, code)#> = true;
  592. ReportPropertyChanged("<#=complexProperty.Name#>");
  593. <#=ChangedMethodName(complexProperty)#>();
  594. }
  595. }
  596. private <#=MultiSchemaEscape(complexProperty.TypeUsage, code)#> <#=code.FieldName(complexProperty)#>;
  597. private bool <#=InitializedTrackingField(complexProperty, code)#>;
  598. partial void <#=ChangingMethodName(complexProperty)#>(<#=MultiSchemaEscape(complexProperty.TypeUsage, code)#> value);
  599. partial void <#=ChangedMethodName(complexProperty)#>();
  600. <#+
  601. }
  602.  
  603. private void WriteLazyLoadingEnabled(EntityContainer container)
  604. {
  605. string lazyLoadingAttributeValue = null;
  606. string lazyLoadingAttributeName = MetadataConstants.EDM_ANNOTATION_09_02 + ":LazyLoadingEnabled";
  607. if(MetadataTools.TryGetStringMetadataPropertySetting(container, lazyLoadingAttributeName, out lazyLoadingAttributeValue))
  608. {
  609. bool isLazyLoading = false;
  610. if(bool.TryParse(lazyLoadingAttributeValue, out isLazyLoading))
  611. {
  612. #>
  613. this.ContextOptions.LazyLoadingEnabled = <#=isLazyLoading.ToString().ToLowerInvariant()#>;
  614. <#+
  615. }
  616. }
  617. }
  618.  
  619. ////////
  620. //////// Declare Template Public Properties.
  621. ////////
  622. public string SourceCsdlPath{ get; set; }
  623. public string ModelNamespace{ get; set; }
  624. public EdmItemCollection ItemCollection{ get; set; }
  625. public IEnumerable<string> ReferenceCsdlPaths{ get; set; }
  626. public Nullable<bool> CreateContextAddToMethods{ get; set; }
  627. public Dictionary<string, string> EdmToObjectNamespaceMap
  628. {
  629. get { return _edmToObjectNamespaceMap; }
  630. set { _edmToObjectNamespaceMap = value; }
  631. }
  632. public Dictionary<string, string> _edmToObjectNamespaceMap = new Dictionary<string, string>();
  633. public Double SourceEdmVersion
  634. {
  635. get
  636. {
  637. if (ItemCollection != null)
  638. {
  639. return ItemCollection.EdmVersion;
  640. }
  641.  
  642. return 0.0;
  643. }
  644. }
  645.  
  646. ////////
  647. //////// Declare Template Private Properties.
  648. ////////
  649. static System.Resources.ResourceManager ResourceManager
  650. {
  651. get
  652. {
  653. if (_resourceManager == null)
  654. {
  655. System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager("System.Data.Entity.Design", typeof(System.Data.Entity.Design.MetadataItemCollectionFactory).Assembly);
  656. System.Threading.Interlocked.CompareExchange(ref _resourceManager, resourceManager, null);
  657. }
  658. return _resourceManager;
  659. }
  660. }
  661. static System.Resources.ResourceManager _resourceManager;
  662.  
  663. #>
  664. <#+
  665.  
  666.  
  667. private static string GetResourceString(string resourceName)
  668. {
  669. return ResourceManager.GetString(resourceName,
  670. null); // Take default culture.
  671. }
  672.  
  673.  
  674.  
  675. private void VerifyTypeUniqueness()
  676. {
  677. HashSet<string> hash = new HashSet<string>();
  678. IEnumerable<GlobalItem> allTypes = GetSourceSchemaTypes<GlobalItem>().Where(i => i is StructuralType || i is EntityContainer);
  679.  
  680. foreach (GlobalItem type in allTypes)
  681. {
  682. if (!hash.Add(GetGlobalItemName(type)))
  683. {
  684. // 6034 is the error number used by System.Data.Entity.Design EntityClassGenerator.
  685. Errors.Add(new System.CodeDom.Compiler.CompilerError(SourceCsdlPath, -1, -1, "6034",
  686. String.Format(CultureInfo.CurrentCulture,
  687. GetResourceString("Template_DuplicateTopLevelType"),
  688. GetGlobalItemName(type))));
  689. }
  690. }
  691. }
  692.  
  693. protected string GetGlobalItemName(GlobalItem item)
  694. {
  695. if (item is EdmType)
  696. {
  697. // EntityType or ComplexType.
  698. return ((EdmType)item).Name;
  699. }
  700. else
  701. {
  702. // Must be an EntityContainer.
  703. return ((EntityContainer)item).Name;
  704. }
  705. }
  706.  
  707.  
  708.  
  709. void ApplyUserSettings(UserSettings userSettings)
  710. {
  711. // Setup template UserSettings.
  712. if (SourceCsdlPath == null)
  713. {
  714. #if !PREPROCESSED_TEMPLATE
  715. if(userSettings.SourceCsdlPath == "$" + "edmxInputFile" + "$")
  716. {
  717. Errors.Add(new System.CodeDom.Compiler.CompilerError(Host.TemplateFile, 0, 0, "",
  718. GetResourceString("Template_ReplaceVsItemTemplateToken")));
  719. return;
  720. }
  721.  
  722. SourceCsdlPath = Host.ResolvePath(userSettings.SourceCsdlPath);
  723. #else
  724. SourceCsdlPath = userSettings.SourceCsdlPath;
  725. #endif
  726. }
  727.  
  728. // normalize the path, remove ..\ from it
  729. SourceCsdlPath = Path.GetFullPath(SourceCsdlPath);
  730.  
  731.  
  732. if (ReferenceCsdlPaths == null)
  733. {
  734. ReferenceCsdlPaths = userSettings.ReferenceCsdlPaths;
  735. }
  736.  
  737. if (!CreateContextAddToMethods.HasValue)
  738. {
  739. CreateContextAddToMethods = userSettings.CreateContextAddToMethods;
  740. }
  741.  
  742. DefaultSummaryComment = GetResourceString("Template_CommentNoDocumentation");
  743. }
  744.  
  745.  
  746. class UserSettings
  747. {
  748. public string SourceCsdlPath{ get; set; }
  749. public string[] ReferenceCsdlPaths{ get; set; }
  750. public bool FullyQualifySystemTypes{ get; set; }
  751. public bool CreateContextAddToMethods{ get; set; }
  752. public bool CamelCaseFields{ get; set; }
  753. }
  754.  
  755. string MultiSchemaEscape(TypeUsage usage, CodeGenerationTools code)
  756. {
  757. StructuralType structural = usage.EdmType as StructuralType;
  758. if (structural != null)
  759. {
  760. return MultiSchemaEscape(structural, code);
  761. }
  762. return code.Escape(usage);
  763. }
  764.  
  765. string MultiSchemaEscape(StructuralType type, CodeGenerationTools code)
  766. {
  767. if (type.NamespaceName != ModelNamespace)
  768. {
  769. return code.CreateFullName(code.EscapeNamespace(GetObjectNamespace(type.NamespaceName)), code.Escape(type));
  770. }
  771.  
  772. return code.Escape(type);
  773. }
  774.  
  775. string NewModifier(NavigationProperty navigationProperty)
  776. {
  777. Type baseType = typeof(object);
  778. return NewModifier(baseType, navigationProperty.Name);
  779. }
  780.  
  781. string NewModifier(EdmFunction edmFunction)
  782. {
  783. Type baseType = typeof(ObjectContext);
  784. return NewModifier(baseType, edmFunction.Name);
  785. }
  786.  
  787. string NewModifier(EntitySet set)
  788. {
  789. Type baseType = typeof(ObjectContext);
  790. return NewModifier(baseType, set.Name);
  791. }
  792.  
  793. string NewModifier(EdmProperty property)
  794. {
  795. Type baseType;
  796. if (property.DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
  797. {
  798. baseType = typeof(EntityObject);
  799. }
  800. else
  801. {
  802. baseType = typeof(ComplexObject);
  803. }
  804. return NewModifier(baseType, property.Name);
  805. }
  806.  
  807. string NewModifier(Type type, string memberName)
  808. {
  809. if (HasBaseMemberWithMatchingName(type, memberName))
  810. {
  811. return "new";
  812. }
  813. return string.Empty;
  814. }
  815.  
  816. static bool HasBaseMemberWithMatchingName(Type type, string memberName)
  817. {
  818. BindingFlags bindingFlags = BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public
  819. | BindingFlags.Instance | BindingFlags.Static;
  820. return type.GetMembers(bindingFlags).Where(m => IsVisibleMember(m)).Any(m => m.Name == memberName);
  821. }
  822.  
  823. string ChangingMethodName(EdmMember member)
  824. {
  825. return string.Format(CultureInfo.InvariantCulture, "On{0}Changing", member.Name);
  826. }
  827.  
  828. string ChangedMethodName(EdmMember member)
  829. {
  830. return string.Format(CultureInfo.InvariantCulture, "On{0}Changed", member.Name);
  831. }
  832.  
  833. string InitializedTrackingField(EdmProperty property, CodeGenerationTools code)
  834. {
  835. string namePart = property.Name + "Initialized";
  836. if (code.CamelCaseFields)
  837. {
  838. namePart = code.CamelCase(namePart);
  839. }
  840. return "_" + namePart;
  841. }
  842.  
  843. string OptionalNullableParameterForSetValidValue(EdmMember member, CodeGenerationTools code)
  844. {
  845. MetadataTools ef = new MetadataTools(this);
  846. string list = string.Empty;
  847. if (((PrimitiveType)member.TypeUsage.EdmType).ClrEquivalentType.IsClass)
  848. {
  849. MetadataProperty storeGeneratedPatternProperty = null;
  850. bool isNullable = ef.IsNullable(member.TypeUsage) ||
  851. (member.MetadataProperties.TryGetValue(MetadataConstants.EDM_ANNOTATION_09_02 + ":StoreGeneratedPattern", false, out storeGeneratedPatternProperty) &&
  852. Object.Equals(storeGeneratedPatternProperty.Value, "Computed"));
  853. list += ", " + code.CreateLiteral(isNullable);
  854. }
  855. return list;
  856. }
  857.  
  858. static bool IsVisibleMember(MemberInfo memberInfo)
  859. {
  860. if (memberInfo is EventInfo)
  861. {
  862. EventInfo ei = (EventInfo)memberInfo;
  863. MethodInfo add = ei.GetAddMethod();
  864. MethodInfo remove = ei.GetRemoveMethod();
  865. return IsVisibleMethod(add) || IsVisibleMethod(remove);
  866. }
  867. else if (memberInfo is FieldInfo)
  868. {
  869. FieldInfo fi = (FieldInfo)memberInfo;
  870. return !fi.IsPrivate && !fi.IsAssembly;
  871. }
  872. else if (memberInfo is MethodBase)
  873. {
  874. MethodBase mb = (MethodBase)memberInfo;
  875. if (mb.IsSpecialName)
  876. return false;
  877. return IsVisibleMethod(mb);
  878. }
  879. else if (memberInfo is PropertyInfo)
  880. {
  881. PropertyInfo pi = (PropertyInfo)memberInfo;
  882. MethodInfo get = pi.GetGetMethod();
  883. MethodInfo set = pi.GetSetMethod();
  884. return IsVisibleMethod(get) || IsVisibleMethod(set);
  885. }
  886.  
  887. return false;
  888. }
  889.  
  890. static bool IsVisibleMethod(MethodBase methodBase)
  891. {
  892. if (methodBase == null)
  893. return false;
  894.  
  895. return !methodBase.IsPrivate && !methodBase.IsAssembly;
  896. }
  897.  
  898. IEnumerable<T> GetSourceSchemaTypes<T>() where T : GlobalItem
  899. {
  900. if (Path.GetExtension(SourceCsdlPath) != ".edmx")
  901. {
  902. return ItemCollection.GetItems<T>().Where(e => e.MetadataProperties.Any(mp => mp.Name == "SchemaSource" && (string)mp.Value == SourceCsdlPath));
  903. }
  904. else
  905. {
  906. return ItemCollection.GetItems<T>();
  907. }
  908. }
  909.  
  910. string EndName(AssociationType association, int index)
  911. {
  912. return association.AssociationEndMembers[index].Name;
  913. }
  914.  
  915. string EndMultiplicity(AssociationType association, int index, CodeGenerationTools code)
  916. {
  917. return code.CreateLiteral(association.AssociationEndMembers[index].RelationshipMultiplicity);
  918. }
  919.  
  920. string EscapeEndTypeName(AssociationType association, int index, CodeGenerationTools code)
  921. {
  922. EntityType entity = association.AssociationEndMembers[index].GetEntityType();
  923. return code.CreateFullName(code.EscapeNamespace(GetObjectNamespace(entity.NamespaceName)), code.Escape(entity));
  924. }
  925.  
  926. string GetObjectNamespace(string csdlNamespaceName)
  927. {
  928. string objectNamespace;
  929. if (EdmToObjectNamespaceMap.TryGetValue(csdlNamespaceName, out objectNamespace))
  930. {
  931. return objectNamespace;
  932. }
  933.  
  934. return csdlNamespaceName;
  935. }
  936.  
  937. void UpdateObjectNamespaceMap(string objectNamespace)
  938. {
  939. if(objectNamespace != ModelNamespace && !EdmToObjectNamespaceMap.ContainsKey(ModelNamespace))
  940. {
  941. EdmToObjectNamespaceMap.Add(ModelNamespace, objectNamespace);
  942. }
  943. }
  944.  
  945. static string FixParameterName(string name, CodeGenerationTools code)
  946. {
  947. // Change any property that is 'id' (case insensitive) to 'ID'
  948. // since 'iD' is a violation of FxCop rules.
  949. if (StringComparer.OrdinalIgnoreCase.Equals(name, "id"))
  950. {
  951. // Return all lower case since it is an abbreviation, not an acronym.
  952. return "id";
  953. }
  954. return code.CamelCase(name);
  955. }
  956.  
  957. string BaseTypeName(EntityType entity, CodeGenerationTools code)
  958. {
  959. return entity.BaseType == null ? "MemoryModel" : MultiSchemaEscape((StructuralType)entity.BaseType, code);
  960. }
  961.  
  962. bool IncludePropertyInFactoryMethod(StructuralType factoryType, EdmProperty edmProperty)
  963. {
  964. if (edmProperty.Nullable)
  965. {
  966. return false;
  967. }
  968.  
  969. if (edmProperty.DefaultValue != null)
  970. {
  971. return false;
  972. }
  973.  
  974. if ((Accessibility.ForReadOnlyProperty(edmProperty) != "public" && Accessibility.ForWriteOnlyProperty(edmProperty) != "public") ||
  975. (factoryType != edmProperty.DeclaringType && Accessibility.ForWriteOnlyProperty(edmProperty) == "private")
  976. )
  977. {
  978. // There is no public part to the property.
  979. return false;
  980. }
  981.  
  982. return true;
  983. }
  984.  
  985.  
  986. class FactoryMethodParameter
  987. {
  988. public EdmProperty Source;
  989. public string RawParameterName;
  990. public string ParameterName;
  991. public string ParameterType;
  992. public string ParameterComment;
  993. public bool IsComplexType;
  994.  
  995. public static IEnumerable<FactoryMethodParameter> CreateParameters(IEnumerable<EdmProperty> properties, UniqueIdentifierService unique, Func<TypeUsage, CodeGenerationTools, string> multiSchemaEscape, CodeGenerationTools code)
  996. {
  997. List<FactoryMethodParameter> parameters = new List<FactoryMethodParameter>();
  998. foreach (EdmProperty property in properties)
  999. {
  1000. FactoryMethodParameter parameter = new FactoryMethodParameter();
  1001. parameter.Source = property;
  1002. parameter.IsComplexType = property.TypeUsage.EdmType is ComplexType;
  1003. parameter.RawParameterName = unique.AdjustIdentifier(FixParameterName(property.Name, code));
  1004. parameter.ParameterName = code.Escape(parameter.RawParameterName);
  1005. parameter.ParameterType = multiSchemaEscape(property.TypeUsage, code);
  1006. parameter.ParameterComment = String.Format(CultureInfo.CurrentCulture, GetResourceString("Template_CommentFactoryMethodParam"), property.Name);
  1007. parameters.Add(parameter);
  1008. }
  1009.  
  1010. return parameters;
  1011. }
  1012. }
  1013.  
  1014. string DefaultSummaryComment{ get; set; }
  1015.  
  1016. string SummaryComment(MetadataItem item)
  1017. {
  1018. if (item.Documentation != null && item.Documentation.Summary != null)
  1019. {
  1020. return PrefixLinesOfMultilineComment(XMLCOMMENT_START + " ", XmlEntityize(item.Documentation.Summary));
  1021. }
  1022.  
  1023. if (DefaultSummaryComment != null)
  1024. {
  1025. return DefaultSummaryComment;
  1026. }
  1027.  
  1028. return string.Empty;
  1029. }
  1030.  
  1031. string LongDescriptionCommentElement(MetadataItem item, int indentLevel)
  1032. {
  1033. if (item.Documentation != null && !String.IsNullOrEmpty(item.Documentation.LongDescription))
  1034. {
  1035. string comment = Environment.NewLine;
  1036. string lineStart = CodeRegion.GetIndent(indentLevel) + XMLCOMMENT_START + " ";
  1037. comment += lineStart + "<LongDescription>" + Environment.NewLine;
  1038. comment += lineStart + PrefixLinesOfMultilineComment(lineStart, XmlEntityize(item.Documentation.LongDescription)) + Environment.NewLine;
  1039. comment += lineStart + "</LongDescription>";
  1040. return comment;
  1041. }
  1042. return string.Empty;
  1043. }
  1044.  
  1045. string PrefixLinesOfMultilineComment(string prefix, string comment)
  1046. {
  1047. return comment.Replace(Environment.NewLine, Environment.NewLine + prefix);
  1048. }
  1049.  
  1050. string ParameterComments(IEnumerable<Tuple<string, string>> parameters, int indentLevel)
  1051. {
  1052. System.Text.StringBuilder builder = new System.Text.StringBuilder();
  1053. foreach (Tuple<string, string> parameter in parameters)
  1054. {
  1055. builder.AppendLine();
  1056. builder.Append(CodeRegion.GetIndent(indentLevel));
  1057. builder.Append(XMLCOMMENT_START);
  1058. builder.Append(String.Format(CultureInfo.InvariantCulture, " <param name=\"{0}\">{1}</param>", parameter.Item1, parameter.Item2));
  1059. }
  1060. return builder.ToString();
  1061. }
  1062.  
  1063. string XmlEntityize(string text)
  1064. {
  1065. if (string.IsNullOrEmpty(text))
  1066. {
  1067. return string.Empty;
  1068. }
  1069.  
  1070. text = text.Replace("&","&amp;");
  1071. text = text.Replace("<","&lt;").Replace(">","&gt;");
  1072. string id = Guid.NewGuid().ToString();
  1073. text = text.Replace(Environment.NewLine, id);
  1074. text = text.Replace("\r", "&#xD;").Replace("\n","&#xA;");
  1075. text = text.Replace(id, Environment.NewLine);
  1076. return text.Replace("\'","&apos;").Replace("\"","&quot;");
  1077. }
  1078.  
  1079. const string XMLCOMMENT_START = "///";
  1080. IEnumerable<EdmProperty> GetProperties(StructuralType type)
  1081. {
  1082. if (type.BuiltInTypeKind == BuiltInTypeKind.EntityType)
  1083. {
  1084. return ((EntityType)type).Properties;
  1085. }
  1086. else
  1087. {
  1088. return ((ComplexType)type).Properties;
  1089. }
  1090. }
  1091.  
  1092. protected void VerifyGetterAndSetterAccessibilityCompatability(EdmMember member)
  1093. {
  1094. string rawGetterAccessibility = Accessibility.ForReadOnlyProperty(member);
  1095. string rawSetterAccessibility = Accessibility.ForWriteOnlyProperty(member);
  1096.  
  1097. if ((rawGetterAccessibility == "internal" && rawSetterAccessibility == "protected") ||
  1098. (rawGetterAccessibility == "protected" && rawSetterAccessibility == "internal"))
  1099.  
  1100. {
  1101. Errors.Add(new System.CodeDom.Compiler.CompilerError(SourceCsdlPath, -1, -1, "6033", String.Format(CultureInfo.CurrentCulture,
  1102. GetResourceString("GeneratedPropertyAccessibilityConflict"),
  1103. member.Name, rawGetterAccessibility, rawSetterAccessibility)));
  1104. }
  1105. }
  1106.  
  1107. private void VerifyEntityTypeAndSetAccessibilityCompatability(EntitySet set)
  1108. {
  1109. string typeAccess = Accessibility.ForType(set.ElementType);
  1110. string setAccess = Accessibility.ForReadOnlyProperty(set);
  1111.  
  1112. if(typeAccess == "internal" && (setAccess == "public" || setAccess == "protected"))
  1113. {
  1114. Errors.Add(new System.CodeDom.Compiler.CompilerError(SourceCsdlPath, -1, -1, "6036", String.Format(CultureInfo.CurrentCulture,
  1115. GetResourceString("EntityTypeAndSetAccessibilityConflict"),
  1116. set.ElementType.Name, typeAccess, set.Name, setAccess)));
  1117. }
  1118. }
  1119.  
  1120. ////////
  1121. //////// UniqueIdentifierService
  1122. ////////
  1123. sealed class UniqueIdentifierService
  1124. {
  1125. private readonly HashSet<string> _knownIdentifiers;
  1126.  
  1127. public UniqueIdentifierService()
  1128. {
  1129. _knownIdentifiers = new HashSet<string>(StringComparer.Ordinal);
  1130. }
  1131.  
  1132. /// <summary>
  1133. /// Makes the supplied identifier unique within the scope by adding
  1134. /// a suffix (1, 2, 3, ...), and returns the unique identifier.
  1135. /// </summary>
  1136. public string AdjustIdentifier(string identifier)
  1137. {
  1138. // find a unique name by adding suffix as necessary
  1139. var numberOfConflicts = 0;
  1140. var adjustedIdentifier = identifier;
  1141.  
  1142. while (!_knownIdentifiers.Add(adjustedIdentifier))
  1143. {
  1144. ++numberOfConflicts;
  1145. adjustedIdentifier = identifier + numberOfConflicts.ToString(CultureInfo.InvariantCulture);
  1146. }
  1147.  
  1148. return adjustedIdentifier;
  1149. }
  1150. }
  1151.  
  1152. #>
  1153.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty