PageRenderTime 35ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/development/Vulcan/Vulcan/Common/Helpers/TableHelper.cs

#
C# | 471 lines | 394 code | 50 blank | 27 comment | 10 complexity | 715b1788b4e83c664d308e70ed1cb588 MD5 | raw file
  1. /*
  2. * Microsoft Public License (Ms-PL)
  3. *
  4. * This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
  5. *
  6. * 1. Definitions
  7. * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
  8. * A "contribution" is the original software, or any additions or changes to the software.
  9. * A "contributor" is any person that distributes its contribution under this license.
  10. * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
  11. *
  12. * 2. Grant of Rights
  13. * (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
  14. * (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
  15. *
  16. * 3. Conditions and Limitations
  17. * (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
  18. * (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
  19. * (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
  20. * (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
  21. * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
  22. */
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Text;
  26. using System.Text.RegularExpressions;
  27. using System.IO;
  28. using System.Xml;
  29. using System.Xml.XPath;
  30. using Vulcan.Common;
  31. using Vulcan.Common.Dimensions;
  32. using Vulcan.Tasks;
  33. using Vulcan.Common.Templates;
  34. using Vulcan.Transformations;
  35. using Vulcan.Emitters;
  36. using Vulcan.Properties;
  37. using DTS = Microsoft.SqlServer.Dts.Runtime;
  38. using Microsoft.SqlServer.Dts.Runtime.Wrapper;
  39. namespace Vulcan.Common
  40. {
  41. public enum KeyColumnType
  42. {
  43. None,
  44. Identity,
  45. PrimaryKey
  46. }
  47. public class TableHelper
  48. {
  49. private string _name;
  50. private VulcanConfig _vulcanConfig;
  51. private XPathNavigator _tableNavigator;
  52. private Dictionary<string,Column> _columnLookup;
  53. private List<Constraint> _constraintList;
  54. private Column _keyColumn;
  55. private KeyColumnType _keyColumnType;
  56. public TableHelper(string name, VulcanConfig vulcanConfig, XPathNavigator tableNavigator)
  57. {
  58. this._name = name;
  59. this._vulcanConfig = vulcanConfig;
  60. this._tableNavigator = tableNavigator;
  61. this._columnLookup = new Dictionary<string,Column>();
  62. this._constraintList = new List<Constraint>();
  63. _ParseColumns();
  64. _ParseKeyColumn();
  65. _PopulateConstraints();
  66. _PopulateDimensions();
  67. }
  68. public Column KeyColumn
  69. {
  70. get
  71. {
  72. return _keyColumn;
  73. }
  74. }
  75. public KeyColumnType KeyColumnType
  76. {
  77. get
  78. {
  79. return _keyColumnType;
  80. }
  81. }
  82. private void _ParseKeyColumn()
  83. {
  84. XPathNavigator keyColumnNav = _tableNavigator.SelectSingleNode("rc:KeyColumn", _vulcanConfig.NamespaceManager);
  85. if (keyColumnNav != null)
  86. {
  87. string name = keyColumnNav.SelectSingleNode("@Name").Value;
  88. string type = keyColumnNav.SelectSingleNode("@Type").Value;
  89. if(this._columnLookup.ContainsKey(name))
  90. {
  91. this._keyColumn = this._columnLookup[name];
  92. switch(type)
  93. {
  94. case "PrimaryKey":
  95. this._keyColumnType = KeyColumnType.PrimaryKey;
  96. break;
  97. case "Identity":
  98. this._keyColumnType = KeyColumnType.Identity;
  99. break;
  100. default:
  101. Message.Trace(Severity.Error,"Unknown key column type {0}",type);
  102. this._keyColumnType = KeyColumnType.None;
  103. break;
  104. }
  105. }
  106. else
  107. {
  108. Message.Trace(Severity.Warning,"Invalid key column {0} in {1}. Skipping",name,this.Name);
  109. return;
  110. }
  111. }
  112. else
  113. {
  114. _keyColumn = null;
  115. _keyColumnType = KeyColumnType.None;
  116. }
  117. }
  118. private void _ParseColumns()
  119. {
  120. foreach (XPathNavigator colNav in _tableNavigator.Select("rc:Columns/rc:Column", _vulcanConfig.NamespaceManager))
  121. {
  122. Column c = new Column();
  123. foreach (XPathNavigator nav in colNav.Select("@*"))
  124. {
  125. c.Properties.Add(nav.Name, nav.Value);
  126. }
  127. if(!_columnLookup.ContainsKey(c.Properties["Name"]))
  128. {
  129. _columnLookup.Add(c.Properties["Name"], c);
  130. }
  131. else
  132. {
  133. Message.Trace(Severity.Error,"Duplicate column {0} in {1}",c.Properties["Name"],this.Name);
  134. return;
  135. }
  136. }
  137. }
  138. private void _PopulateDimensions()
  139. {
  140. foreach (XPathNavigator dimNav in _tableNavigator.Select("rc:Columns/rc:Dimension", _vulcanConfig.NamespaceManager))
  141. {
  142. string dimName = dimNav.SelectSingleNode("@Name").Value;
  143. string factTableDimColumnName = dimNav.SelectSingleNode("@OutputName").Value;
  144. Message.Trace(Severity.Debug,"Mapping {0} to Dimension {1}", _name, dimName);
  145. if (DimensionHelper.DimDictionary.ContainsKey(dimName))
  146. {
  147. TableHelper dimTableHelper =
  148. new TableHelper(
  149. dimName,
  150. DimensionHelper.DimDictionary[dimName],
  151. DimensionHelper.DimNavigatorDictionary[dimName].SelectSingleNode("rc:Table",_vulcanConfig.NamespaceManager));
  152. Column dimKeyColumn = dimTableHelper.KeyColumn;
  153. if (dimKeyColumn != null)
  154. {
  155. string constraintName = String.Format(System.Globalization.CultureInfo.InvariantCulture,"{0}_{1}_{2}", _name, dimName, factTableDimColumnName);
  156. //Clone the Foreign Key Column and add it into our fact table.
  157. Column tableColumn = (Column)dimKeyColumn.Clone();
  158. tableColumn.Properties["Name"] = factTableDimColumnName;
  159. this.Columns.Add(factTableDimColumnName,tableColumn);
  160. ForeignKeyConstraint fkc = new ForeignKeyConstraint(constraintName, tableColumn, dimKeyColumn, dimName);
  161. this.Constraints.Add(fkc);
  162. }
  163. else
  164. {
  165. dimTableHelper.TraceHelper();
  166. Message.Trace(Severity.Error,"Dimension {0} has no key column.\n{1}", dimName,dimTableHelper.TableNavigator.OuterXml);
  167. }
  168. }
  169. else
  170. {
  171. Message.Trace(Severity.Error,"Dimension {0} cannot be found in the Dimensions Database.", dimName);
  172. }
  173. }
  174. }
  175. private SimpleConstraint _ParseSimpleConstraint(XPathNavigator simpleConstraintNav, bool isPrimaryKey, int index)
  176. {
  177. SimpleConstraint sc;
  178. List<Column> localColumnList = new List<Column>();
  179. foreach (XPathNavigator colNav in simpleConstraintNav.Select("rc:Column", _vulcanConfig.NamespaceManager))
  180. {
  181. Column c = new Column();
  182. foreach (XPathNavigator nav in colNav.Select("@*"))
  183. {
  184. c.Properties.Add(nav.Name, nav.Value);
  185. }
  186. localColumnList.Add(c);
  187. }
  188. if (isPrimaryKey)
  189. {
  190. string name = String.Format(System.Globalization.CultureInfo.InvariantCulture, "PK_{0}_{1}", _name, index, localColumnList);
  191. sc = new PrimaryKeyConstraint(name, localColumnList);
  192. }
  193. else
  194. {
  195. string name = String.Format(System.Globalization.CultureInfo.InvariantCulture, "CON_{0}_{1}", _name, index, localColumnList);
  196. sc = new SimpleConstraint(name, localColumnList);
  197. }
  198. foreach (XPathNavigator attributeNav in simpleConstraintNav.Select("@*"))
  199. {
  200. sc.Properties.Add(attributeNav.Name, attributeNav.Value);
  201. }
  202. return sc;
  203. }
  204. private void _PopulateConstraints()
  205. {
  206. int index = 0;
  207. foreach (XPathNavigator conNav in _tableNavigator.Select("rc:Constraints/rc:PrimaryKeyConstraint", _vulcanConfig.NamespaceManager))
  208. {
  209. _constraintList.Add(_ParseSimpleConstraint(conNav,true,index));
  210. index++;
  211. }
  212. index = 0;
  213. foreach (XPathNavigator conNav in _tableNavigator.Select("rc:Constraints/rc:Constraint", _vulcanConfig.NamespaceManager))
  214. {
  215. _constraintList.Add(_ParseSimpleConstraint(conNav, false, index));
  216. index++;
  217. }
  218. foreach (XPathNavigator fkCon in _tableNavigator.Select("rc:Constraints/rc:ForeignKeyConstraint", _vulcanConfig.NamespaceManager))
  219. {
  220. Column localColumn = new Column();
  221. Column foreignColumn = new Column();
  222. foreach (XPathNavigator nav in fkCon.Select("rc:LocalColumn/@*", _vulcanConfig.NamespaceManager))
  223. {
  224. localColumn.Properties[nav.Name] = nav.Value;
  225. }
  226. foreach (XPathNavigator nav in fkCon.Select("rc:ForeignColumn/@*", _vulcanConfig.NamespaceManager))
  227. {
  228. foreignColumn.Properties[nav.Name] = nav.Value;
  229. }
  230. string fkName = String.Format(System.Globalization.CultureInfo.InvariantCulture,"FK_{0}_{1}_{2}_{3}",_name,localColumn.Name,foreignColumn.Properties["Table"],foreignColumn.Name);
  231. ForeignKeyConstraint fkc = new ForeignKeyConstraint(fkName, localColumn, foreignColumn, foreignColumn.Properties["Table"]);
  232. _constraintList.Add(fkc);
  233. }
  234. }
  235. public bool IsIdentityColumn(string name)
  236. {
  237. bool isIdentity = (
  238. (KeyColumnType == KeyColumnType.Identity)
  239. &&
  240. (KeyColumn.Name.ToUpperInvariant() == name.ToUpperInvariant())
  241. );
  242. return isIdentity;
  243. }
  244. public void TraceHelper()
  245. {
  246. Message.Trace(Severity.Debug, "TableHelper for table {0}", _name);
  247. foreach (Column c in _columnLookup.Values)
  248. {
  249. Message.Trace(Severity.Debug, "Table {0}: Column: {1}: Type {2}", _name, c.Properties["Name"], c.Properties["Type"]);
  250. }
  251. foreach (Constraint c in this._constraintList)
  252. {
  253. Message.Trace(Severity.Debug, "Constraint {0}", c.Name);
  254. }
  255. }
  256. public string Name
  257. {
  258. get
  259. {
  260. return this._name;
  261. }
  262. }
  263. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
  264. public Dictionary<string,Column> Columns
  265. {
  266. get
  267. {
  268. return this._columnLookup;
  269. }
  270. }
  271. public List<Constraint> Constraints
  272. {
  273. get
  274. {
  275. return this._constraintList;
  276. }
  277. }
  278. public XPathNavigator TableNavigator
  279. {
  280. get
  281. {
  282. return this._tableNavigator;
  283. }
  284. }
  285. } // End TableHelper
  286. public class PrimaryKeyConstraint : SimpleConstraint
  287. {
  288. public PrimaryKeyConstraint(string name, Column c)
  289. :
  290. base(name,c)
  291. {
  292. }
  293. public PrimaryKeyConstraint(string name, List<Column> columnList)
  294. :
  295. base(name,columnList)
  296. {
  297. }
  298. }
  299. public class SimpleConstraint : Constraint
  300. {
  301. private List<Column> _columnList;
  302. public SimpleConstraint(string name, Column c)
  303. :
  304. base(name)
  305. {
  306. _columnList = new List<Column>();
  307. _columnList.Add(c);
  308. }
  309. public SimpleConstraint(string name, List<Column> columnList)
  310. :
  311. base(name)
  312. {
  313. _columnList = columnList;
  314. }
  315. public List<Column> Columns
  316. {
  317. get
  318. {
  319. return this._columnList;
  320. }
  321. }
  322. }
  323. public class ForeignKeyConstraint : Constraint
  324. {
  325. private Column _localColumn;
  326. private Column _foreignColumn;
  327. private string _foreignTable;
  328. public ForeignKeyConstraint(string name, Column localColumn, Column foreignColumn, string foreignTable)
  329. :
  330. base(name)
  331. {
  332. _localColumn = localColumn;
  333. _foreignColumn = foreignColumn;
  334. _foreignTable = foreignTable;
  335. }
  336. public Column LocalColumn
  337. {
  338. get
  339. {
  340. return _localColumn;
  341. }
  342. }
  343. public Column ForeignColumn
  344. {
  345. get
  346. {
  347. return _foreignColumn;
  348. }
  349. }
  350. public string ForeignTable
  351. {
  352. get
  353. {
  354. return _foreignTable;
  355. }
  356. }
  357. }
  358. public abstract class Constraint
  359. {
  360. private string _name;
  361. private Dictionary<string, string> _properties;
  362. protected Constraint(string name)
  363. {
  364. _name= name;
  365. _properties = new Dictionary<string, string>();
  366. }
  367. public string Name
  368. {
  369. get
  370. {
  371. return this._name;
  372. }
  373. }
  374. public Dictionary<string, string> Properties
  375. {
  376. get
  377. {
  378. return this._properties;
  379. }
  380. }
  381. }
  382. public class Column : ICloneable
  383. {
  384. private Dictionary<string, string> _properties;
  385. public Column()
  386. {
  387. _properties = new Dictionary<string, string>();
  388. }
  389. public Dictionary<string, string> Properties
  390. {
  391. get
  392. {
  393. return this._properties;
  394. }
  395. }
  396. public string Name
  397. {
  398. get
  399. {
  400. return _properties["Name"];
  401. }
  402. set
  403. {
  404. _properties["Name"] = value;
  405. }
  406. }
  407. /// <summary>
  408. /// Performs a deep clone of the Column
  409. /// </summary>
  410. /// <returns>Column which was cloned.</returns>
  411. public Object Clone()
  412. {
  413. Column c = new Column();
  414. foreach (string s in this._properties.Keys)
  415. {
  416. c.Properties[s] = _properties[s];
  417. }
  418. return c;
  419. }
  420. }
  421. } // End Namespace