TableKey.tt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. <#@ template language="C#" debug="false" hostspecific="true"#>
  2. <#@ include file="EF.Utility.CS.ttinclude"#>
  3. <#@ assembly name="$(DevEnvDir)Microsoft.Data.Entity.Design.DatabaseGeneration.dll"#>
  4. <#@ assembly name="$(SolutionDir)\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.dll"#>
  5. <#@ import namespace="Microsoft.Data.Entity.Design.DatabaseGeneration" #>
  6. <#@ import namespace="System.Text"#>
  7. <#@ output extension=".cs"#><#
  8. CodeGenerationTools code = new CodeGenerationTools(this);
  9. CodeRegion region = new CodeRegion(this, 1);
  10. MetadataTools ef = new MetadataTools(this);
  11. string inputFile = @"EMISContext.edmx";
  12. var loadResult = LoadMetadata(inputFile);
  13. EdmItemCollection itemCollection = loadResult.EdmItems;
  14. var propertyToColumnMapping = loadResult.PropertyToColumnMapping;
  15. var manyToManyMappings = loadResult.ManyToManyMappings;
  16. var tphMappings = loadResult.TphMappings;
  17. string namespaceName = code.VsNamespaceSuggestion();
  18. EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
  19. WriteHeader(fileManager);#>
  20. using System.Collections.Generic;
  21. namespace EMIS.Entities
  22. {
  23. public class TableKeyDictionary
  24. {
  25. private static Dictionary<string, string> items;
  26. public static Dictionary<string, string> Items
  27. {
  28. get { return items; }
  29. }
  30. static TableKeyDictionary()
  31. {
  32. items = new Dictionary<string, string>();
  33. <#foreach (EntityType entity in itemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
  34. {
  35. string hasKey;
  36. hasKey = string.Format("items.Add(\"{0}\", \"{1}\");", entity.Name, entity.KeyMembers[0].Name);#>
  37. <#=hasKey#>
  38. <#}
  39. #>
  40. }
  41. public static string GetKeyName<TEntity>(TEntity entity)
  42. {
  43. string tableName = entity.GetType().Name;
  44. return items[tableName];
  45. }
  46. public static string GetKeyName<TEntity>()
  47. {
  48. string tableName = typeof(TEntity).Name;
  49. return items[tableName];
  50. }
  51. }
  52. }
  53. <#+
  54. string GetResourceString(string resourceName)
  55. {
  56. if(_resourceManager2 == null)
  57. {
  58. _resourceManager2 = new System.Resources.ResourceManager("System.Data.Entity.Design", typeof(System.Data.Entity.Design.MetadataItemCollectionFactory).Assembly);
  59. }
  60. return _resourceManager2.GetString(resourceName, null);
  61. }
  62. System.Resources.ResourceManager _resourceManager2;
  63. void WriteHeader(EntityFrameworkTemplateFileManager fileManager)
  64. {
  65. fileManager.StartHeader();
  66. #>
  67. //------------------------------------------------------------------------------
  68. // <auto-generated>
  69. // This code was generated from a template.
  70. //
  71. // Manual changes to this file may cause unexpected behavior in your application.
  72. // Manual changes to this file will be overwritten if the code is regenerated.
  73. // </auto-generated>
  74. //------------------------------------------------------------------------------
  75. <#+
  76. fileManager.EndBlock();
  77. }
  78. void BeginNamespace(string namespaceName, CodeGenerationTools code)
  79. {
  80. CodeRegion region = new CodeRegion(this);
  81. if (!String.IsNullOrEmpty(namespaceName))
  82. {
  83. #>
  84. namespace <#=code.EscapeNamespace(namespaceName)#>
  85. {
  86. <#+
  87. PushIndent(CodeRegion.GetIndent(1));
  88. }
  89. }
  90. void EndNamespace(string namespaceName)
  91. {
  92. if (!String.IsNullOrEmpty(namespaceName))
  93. {
  94. PopIndent();
  95. #>
  96. }
  97. <#+
  98. }
  99. }
  100. string ToTable(EntitySet entitySet)
  101. {
  102. var toTable = entitySet.Name;
  103. string schema = entitySet.GetSchemaName();
  104. if(!string.IsNullOrWhiteSpace(schema) && schema != "dbo")
  105. toTable += "\", \"" + schema;
  106. return toTable;
  107. }
  108. bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection)
  109. {
  110. var alreadySeen = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
  111. foreach(var type in itemCollection.GetItems<StructuralType>())
  112. {
  113. if (!(type is EntityType || type is ComplexType))
  114. {
  115. continue;
  116. }
  117. if (alreadySeen.ContainsKey(type.FullName))
  118. {
  119. Error(String.Format(CultureInfo.CurrentCulture, "This template does not support types that differ only by case, the types {0} are not supported", type.FullName));
  120. return false;
  121. }
  122. else
  123. {
  124. alreadySeen.Add(type.FullName, true);
  125. }
  126. }
  127. return true;
  128. }
  129. string GetGenerationOption(EdmProperty property, EntityType entity)
  130. {
  131. string result = "";
  132. bool isPk = entity.KeyMembers.Contains(property);
  133. MetadataProperty storeGeneratedPatternProperty = null;
  134. string storeGeneratedPatternPropertyValue = "None";
  135. if(property.MetadataProperties.TryGetValue(MetadataConsts.EDM_ANNOTATION_09_02 + ":StoreGeneratedPattern", false, out storeGeneratedPatternProperty))
  136. storeGeneratedPatternPropertyValue = storeGeneratedPatternProperty.Value.ToString();
  137. PrimitiveType edmType = (PrimitiveType) property.TypeUsage.EdmType;
  138. if (storeGeneratedPatternPropertyValue == "Computed")
  139. {
  140. result = ".HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)";
  141. }
  142. else if ((edmType.ClrEquivalentType == typeof(int)) || (edmType.ClrEquivalentType == typeof(short)) || (edmType.ClrEquivalentType == typeof(long)))
  143. {
  144. if (isPk && (storeGeneratedPatternPropertyValue != "Identity"))
  145. result = ".HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)";
  146. else if ((!isPk || (entity.KeyMembers.Count > 1)) && (storeGeneratedPatternPropertyValue == "Identity"))
  147. result = ".HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)";
  148. }
  149. return result;
  150. }
  151. MetadataLoadResult LoadMetadata(string inputFile)
  152. {
  153. var loader = new MetadataLoader(this);
  154. bool loaded = false;
  155. EdmItemCollection edmItemCollection = loader.CreateEdmItemCollection(inputFile);
  156. StoreItemCollection storeItemCollection = null;
  157. if (loader.TryCreateStoreItemCollection(inputFile, out storeItemCollection))
  158. {
  159. StorageMappingItemCollection storageMappingItemCollection;
  160. if (loader.TryCreateStorageMappingItemCollection(inputFile, edmItemCollection, storeItemCollection, out storageMappingItemCollection))
  161. loaded = true;
  162. }
  163. if(loaded == false)
  164. throw new Exception("Cannot load a metadata from the file " + inputFile);
  165. var mappingMetadata = LoadMappingMetadata(inputFile);
  166. var mappingNode = mappingMetadata.Item1;
  167. var nsmgr = mappingMetadata.Item2;
  168. var allEntitySets = storeItemCollection.GetAllEntitySets();
  169. return new MetadataLoadResult
  170. {
  171. EdmItems = edmItemCollection,
  172. PropertyToColumnMapping = BuildEntityMappings(mappingNode, nsmgr, edmItemCollection.GetItems<EntityType>(), edmItemCollection.GetAllEntitySets(), allEntitySets),
  173. ManyToManyMappings = BuildManyToManyMappings(mappingNode, nsmgr, edmItemCollection.GetAllAssociationSets(), allEntitySets),
  174. TphMappings=BuildTPHMappings(mappingNode, nsmgr, edmItemCollection.GetItems<EntityType>(), edmItemCollection.GetAllEntitySets(), allEntitySets)
  175. };
  176. }
  177. private Tuple<XmlNode, XmlNamespaceManager> LoadMappingMetadata(string inputFile)
  178. {
  179. var xmlDoc = new XmlDocument();
  180. xmlDoc.Load(Host.ResolvePath(inputFile));
  181. var schemaConstantsList = new SchemaConsts[]
  182. {
  183. MetadataConsts.V2_SCHEMA_CONSTANTS,
  184. MetadataConsts.V1_SCHEMA_CONSTANTS
  185. };
  186. foreach (var schemaConstants in schemaConstantsList)
  187. {
  188. var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
  189. nsmgr.AddNamespace("ef", schemaConstants.MslNamespace);
  190. nsmgr.AddNamespace("edmx", schemaConstants.EdmxNamespace);
  191. var mappingNode = xmlDoc.DocumentElement.SelectSingleNode("./*/edmx:Mappings", nsmgr);
  192. if(mappingNode != null)
  193. return Tuple.Create(mappingNode, nsmgr);
  194. }
  195. throw new Exception(GetResourceString("Template_UnsupportedSchema"));
  196. }
  197. private Dictionary<EntityType, Dictionary<EntityType, Dictionary<EdmProperty, string>>> BuildTPHMappings(XmlNode mappingNode, XmlNamespaceManager nsmgr, IEnumerable<EntityType> entityTypes, IEnumerable<EntitySet> entitySets, IEnumerable<EntitySet> tableSets)
  198. {
  199. var dictionary = new Dictionary<EntityType, Dictionary<EntityType, Dictionary<EdmProperty, string>>>();
  200. foreach (EntitySet set in entitySets)
  201. {
  202. XmlNodeList nodes = mappingNode.SelectNodes(string.Format(".//ef:EntitySetMapping[@Name=\"{0}\"]/ef:EntityTypeMapping/ef:MappingFragment", set.Name), nsmgr);
  203. foreach(XmlNode node in nodes)
  204. {
  205. string typeName=node.ParentNode.Attributes["TypeName"].Value;
  206. if(typeName.StartsWith("IsTypeOf("))
  207. typeName=typeName.Substring("IsTypeOf(".Length, typeName.Length-"IsTypeOf()".Length);
  208. EntityType type=entityTypes.Single(z=>z.FullName==typeName);
  209. string tableName = node.Attributes["StoreEntitySet"].Value;
  210. EntitySet set2 = tableSets.Single(entitySet => entitySet.Name == tableName);
  211. var entityMap = new Dictionary<EdmProperty, string>();
  212. XmlNodeList propertyNodes = node.SelectNodes("./ef:Condition", nsmgr);
  213. if(propertyNodes.Count==0) continue;
  214. foreach(XmlNode propertyNode in propertyNodes)
  215. {
  216. string str = propertyNode.Attributes["ColumnName"].Value;
  217. EdmProperty property2 = set2.ElementType.Properties[str];
  218. string val=propertyNode.Attributes["Value"].Value;
  219. entityMap.Add(property2, val);
  220. }
  221. EntityType baseType=(EntityType)(type.BaseType??type);
  222. if(!dictionary.Keys.Contains(baseType))
  223. {
  224. var entityMappings=new Dictionary<EntityType, Dictionary<EdmProperty, string>>();
  225. //entityMappings.Add(type,entityMap);
  226. dictionary.Add(baseType, entityMappings);
  227. }
  228. dictionary[baseType].Add(type,entityMap);
  229. }
  230. }
  231. return dictionary;
  232. }
  233. private Dictionary<EntityType, Tuple<EntitySet, Dictionary<EdmProperty, EdmProperty>>> BuildEntityMappings(XmlNode mappingNode, XmlNamespaceManager nsmgr, IEnumerable<EntityType> entityTypes, IEnumerable<EntitySet> entitySets, IEnumerable<EntitySet> tableSets)
  234. {
  235. var dictionary = new Dictionary<EntityType, Tuple<EntitySet, Dictionary<EdmProperty, EdmProperty>>>();
  236. foreach (EntitySet set in entitySets)
  237. {
  238. XmlNodeList nodes = mappingNode.SelectNodes(string.Format(".//ef:EntitySetMapping[@Name=\"{0}\"]/ef:EntityTypeMapping/ef:MappingFragment", set.Name), nsmgr);
  239. foreach(XmlNode node in nodes)
  240. {
  241. string typeName=node.ParentNode.Attributes["TypeName"].Value;
  242. if(typeName.StartsWith("IsTypeOf("))
  243. typeName=typeName.Substring("IsTypeOf(".Length, typeName.Length-"IsTypeOf()".Length);
  244. EntityType type=entityTypes.Single(z=>z.FullName==typeName);
  245. string tableName = node.Attributes["StoreEntitySet"].Value;
  246. EntitySet set2 = tableSets.Single(entitySet => entitySet.Name == tableName);
  247. var entityMap = new Dictionary<EdmProperty, EdmProperty>();
  248. foreach (EdmProperty property in type.Properties)
  249. {
  250. XmlNode propertyNode = node.SelectSingleNode(string.Format("./ef:ScalarProperty[@Name=\"{0}\"]", property.Name), nsmgr);
  251. if(propertyNode == null) continue;
  252. string str = propertyNode.Attributes["ColumnName"].Value;
  253. EdmProperty property2 = set2.ElementType.Properties[str];
  254. entityMap.Add(property, property2);
  255. }
  256. dictionary.Add(type, Tuple.Create(set2, entityMap));
  257. }
  258. }
  259. return dictionary;
  260. }
  261. Dictionary<AssociationType, Tuple<EntitySet, Dictionary<RelationshipEndMember, Dictionary<EdmMember, string>>>> BuildManyToManyMappings(XmlNode mappingNode, XmlNamespaceManager nsmgr, IEnumerable<AssociationSet> associationSets, IEnumerable<EntitySet> tableSets)
  262. {
  263. var dictionary = new Dictionary<AssociationType, Tuple<EntitySet, Dictionary<RelationshipEndMember, Dictionary<EdmMember, string>>>>();
  264. foreach (AssociationSet associationSet in associationSets.Where(set => set.ElementType.IsManyToMany()))
  265. {
  266. XmlNode node = mappingNode.SelectSingleNode(string.Format("//ef:AssociationSetMapping[@Name=\"{0}\"]", associationSet.Name), nsmgr);
  267. string tableName = node.Attributes["StoreEntitySet"].Value;
  268. EntitySet entitySet = tableSets.Single(s => s.Name == tableName);
  269. var relationEndMap = new Dictionary<RelationshipEndMember, Dictionary<EdmMember, string>>();
  270. foreach (AssociationSetEnd end in associationSet.AssociationSetEnds)
  271. {
  272. var map = new Dictionary<EdmMember, string>();
  273. foreach (XmlNode endProperty in node.SelectSingleNode(string.Format("./ef:EndProperty[@Name=\"{0}\"]", end.Name), nsmgr).ChildNodes)
  274. {
  275. string str = endProperty.Attributes["Name"].Value;
  276. EdmProperty key = end.EntitySet.ElementType.Properties[str];
  277. string str2 = endProperty.Attributes["ColumnName"].Value;
  278. map.Add(key, str2);
  279. }
  280. relationEndMap.Add(end.CorrespondingAssociationEndMember, map);
  281. }
  282. dictionary.Add(associationSet.ElementType, Tuple.Create(entitySet, relationEndMap));
  283. }
  284. return dictionary;
  285. }
  286. public class MetadataLoadResult
  287. {
  288. public EdmItemCollection EdmItems { get; set; }
  289. public Dictionary<EntityType, Tuple<EntitySet, Dictionary<EdmProperty, EdmProperty>>> PropertyToColumnMapping { get; set; }
  290. public Dictionary<AssociationType, Tuple<EntitySet, Dictionary<RelationshipEndMember, Dictionary<EdmMember, string>>>> ManyToManyMappings { get; set; }
  291. public Dictionary<EntityType, Dictionary<EntityType, Dictionary<EdmProperty, string>>> TphMappings { get; set; }
  292. }
  293. /// <summary>
  294. /// Responsible for encapsulating the constants defined in Metadata
  295. /// </summary>
  296. public static class MetadataConsts
  297. {
  298. public const string CSDL_EXTENSION = ".csdl";
  299. public const string CSDL_EDMX_SECTION_NAME = "ConceptualModels";
  300. public const string CSDL_ROOT_ELEMENT_NAME = "Schema";
  301. public const string EDM_ANNOTATION_09_02 = "http://schemas.microsoft.com/ado/2009/02/edm/annotation";
  302. public const string SSDL_EXTENSION = ".ssdl";
  303. public const string SSDL_EDMX_SECTION_NAME = "StorageModels";
  304. public const string SSDL_ROOT_ELEMENT_NAME = "Schema";
  305. public const string MSL_EXTENSION = ".msl";
  306. public const string MSL_EDMX_SECTION_NAME = "Mappings";
  307. public const string MSL_ROOT_ELEMENT_NAME = "Mapping";
  308. public const string TT_TEMPLATE_NAME = "TemplateName";
  309. public const string TT_TEMPLATE_VERSION = "TemplateVersion";
  310. public const string TT_MINIMUM_ENTITY_FRAMEWORK_VERSION = "MinimumEntityFrameworkVersion";
  311. public const string DEFAULT_TEMPLATE_VERSION = "4.0";
  312. public static readonly SchemaConsts V1_SCHEMA_CONSTANTS = new SchemaConsts(
  313. "http://schemas.microsoft.com/ado/2007/06/edmx",
  314. "http://schemas.microsoft.com/ado/2006/04/edm",
  315. "http://schemas.microsoft.com/ado/2006/04/edm/ssdl",
  316. "urn:schemas-microsoft-com:windows:storage:mapping:CS",
  317. new Version("3.5"));
  318. public static readonly SchemaConsts V2_SCHEMA_CONSTANTS = new SchemaConsts(
  319. "http://schemas.microsoft.com/ado/2008/10/edmx",
  320. "http://schemas.microsoft.com/ado/2008/09/edm",
  321. "http://schemas.microsoft.com/ado/2009/02/edm/ssdl",
  322. "http://schemas.microsoft.com/ado/2008/09/mapping/cs",
  323. new Version("4.0"));
  324. public static readonly SchemaConsts V3_SCHEMA_CONSTANTS = new SchemaConsts(
  325. "http://schemas.microsoft.com/ado/2009/11/edmx",
  326. "http://schemas.microsoft.com/ado/2009/11/edm",
  327. "http://schemas.microsoft.com/ado/2009/11/edm/ssdl",
  328. "http://schemas.microsoft.com/ado/2009/11/mapping/cs",
  329. new Version("4.5"));
  330. }
  331. public struct SchemaConsts
  332. {
  333. public SchemaConsts(string edmxNamespace, string csdlNamespace, string ssdlNamespace, string mslNamespace, Version minimumTemplateVersion) : this()
  334. {
  335. EdmxNamespace = edmxNamespace;
  336. CsdlNamespace = csdlNamespace;
  337. SsdlNamespace = ssdlNamespace;
  338. MslNamespace = mslNamespace;
  339. MinimumTemplateVersion = minimumTemplateVersion;
  340. }
  341. public string EdmxNamespace { get; private set; }
  342. public string CsdlNamespace { get; private set; }
  343. public string SsdlNamespace { get; private set; }
  344. public string MslNamespace { get; private set; }
  345. public Version MinimumTemplateVersion { get; private set; }
  346. }
  347. #>