PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/EntityGenerator/MainForm.cs

https://github.com/RickyLin/DotNetUtilities
C# | 590 lines | 462 code | 70 blank | 58 comment | 49 complexity | 39d7aa6035b7c234800850ce4c95fc4a MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Threading.Tasks;
  10. using Microsoft.Practices.EnterpriseLibrary.Data;
  11. using System.Data.Common;
  12. using System.Configuration;
  13. using System.IO;
  14. using System.Data.Entity.Design.PluralizationServices;
  15. using System.Globalization;
  16. namespace EntityGenerator
  17. {
  18. public partial class MainForm : Form
  19. {
  20. private string _DefaultNamespace;
  21. private string _OutputPath;
  22. private ListItem[] _SelectedItems;
  23. private CodeType _CodeType;
  24. private string _DbContextName;
  25. private PluralizationService _PluralizationSvc;
  26. public MainForm()
  27. {
  28. InitializeComponent();
  29. }
  30. private void MainForm_Load(object sender, EventArgs e)
  31. {
  32. Task.Factory.StartNew(LoadTables);
  33. Task.Factory.StartNew(LoadViews);
  34. tbPath.Text = Path.Combine(Environment.CurrentDirectory, "Output");
  35. _PluralizationSvc = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en-us"));
  36. tbDefaultNamespace.Text = ConfigurationManager.AppSettings["defaultNamespace"];
  37. }
  38. private void LoadViews()
  39. {
  40. FillOutDatabaseObjectNames("cmdQueryViews", clbViews, DatabaseObjectType.View);
  41. }
  42. private void LoadTables()
  43. {
  44. FillOutDatabaseObjectNames("cmdQueryTables", clbTables, DatabaseObjectType.Table);
  45. }
  46. private void FillOutDatabaseObjectNames(string cmdName, CheckedListBox clb, DatabaseObjectType objectType)
  47. {
  48. string objectName;
  49. string strCmd = ConfigurationManager.AppSettings[cmdName];
  50. Database db = DatabaseFactory.CreateDatabase();
  51. Action beginUpdate = () => clb.BeginUpdate();
  52. clb.Invoke(beginUpdate);
  53. using (IDataReader reader = db.ExecuteReader(CommandType.Text, strCmd))
  54. {
  55. Action addItem;
  56. while (reader.Read())
  57. {
  58. objectName = reader.GetString(0);
  59. addItem = () => clb.Items.Add(new ListItem() { Value = objectName, Type = objectType });
  60. clb.Invoke(addItem);
  61. }
  62. }
  63. Action endUpdate = () => clb.EndUpdate();
  64. clb.Invoke(endUpdate);
  65. }
  66. private void cbAllTables_CheckedChanged(object sender, EventArgs e)
  67. {
  68. SetAllDatabaseObjectSelected(clbTables, cbAllTables);
  69. }
  70. private void cbAllViews_CheckedChanged(object sender, EventArgs e)
  71. {
  72. SetAllDatabaseObjectSelected(clbViews, cbAllViews);
  73. }
  74. private void SetAllDatabaseObjectSelected(CheckedListBox dbObjectList, CheckBox chkAll)
  75. {
  76. dbObjectList.BeginUpdate();
  77. for (int i = 0; i < dbObjectList.Items.Count; i++)
  78. {
  79. dbObjectList.SetItemChecked(i, chkAll.Checked);
  80. }
  81. dbObjectList.EndUpdate();
  82. }
  83. private void btnGenerate_Click(object sender, EventArgs e)
  84. {
  85. lbOutputs.Items.Clear();
  86. ListItem[] items = new ListItem[clbTables.CheckedItems.Count + clbViews.CheckedItems.Count];
  87. int itemIndex = 0;
  88. foreach (object item in clbTables.CheckedItems)
  89. {
  90. items[itemIndex] = item as ListItem;
  91. itemIndex++;
  92. }
  93. foreach (object item in clbViews.CheckedItems)
  94. {
  95. items[itemIndex] = item as ListItem;
  96. itemIndex++;
  97. }
  98. _SelectedItems = items;
  99. _CodeType = rbEntities.Checked ? CodeType.Entities : CodeType.DbContext;
  100. _DbContextName = tbDbContextName.Text;
  101. _DefaultNamespace = tbDefaultNamespace.Text;
  102. _OutputPath = tbPath.Text.EndsWith("\\") ? tbPath.Text : tbPath.Text + "\\";
  103. if (Directory.Exists(_OutputPath) == false)
  104. Directory.CreateDirectory(_OutputPath);
  105. Task.Factory.StartNew(StartToGenerate);
  106. }
  107. private void StartToGenerate()
  108. {
  109. ParallelLoopResult result;
  110. switch (_CodeType)
  111. {
  112. case CodeType.Entities:
  113. result = Parallel.ForEach(_SelectedItems, GenerateEntityObject);
  114. break;
  115. case CodeType.DbContext:
  116. //result = Parallel.ForEach(_SelectedItems, GenerateDbContext);
  117. Task t = Task.Factory.StartNew(GenerateDbContext);
  118. t.Wait();
  119. break;
  120. }
  121. Action addDone = () => lbOutputs.Items.Add("All done.");
  122. lbOutputs.Invoke(addDone);
  123. }
  124. private string GetTypeName(int dbTypeID, bool isNullable)
  125. {
  126. DataType[] types = GetDataTypes();
  127. DataType dt = types.FirstOrDefault(t => t.DbTypeID == dbTypeID);
  128. if (dt == null)
  129. {
  130. return "ERROR_DbType_" + dbTypeID.ToString();
  131. }
  132. return isNullable ? dt.NullableTypeName : dt.TypeName;
  133. }
  134. private DataType[] GetDataTypes()
  135. {
  136. DataType[] types = {
  137. new DataType(34, "image", "byte[]", "byte[]"),
  138. new DataType(35, "text", "string", "string"),
  139. new DataType(36, "uniqueidentifier", "Guid", "Guid?"),
  140. new DataType(40, "date", "DateTime", "DateTime?"),
  141. new DataType(41, "time", "TimeSpan", "TimeSpan?"),
  142. //new DataType(42, "datetime2", "", ""),
  143. //new DataType(43, "datetimeoffset", "", ""),
  144. new DataType(48, "tinyint", "byte", "byte?"),
  145. new DataType(52, "smallint", "short", "short?"),
  146. new DataType(56, "int", "int", "int?"),
  147. new DataType(58, "smalldatetime", "DateTime", "DateTime?"),
  148. new DataType(59, "real", "float", "float?"),
  149. new DataType(60, "money", "decimal", "decimal?"),
  150. new DataType(61, "datetime", "DateTime", "DateTime?"),
  151. new DataType(62, "float", "double", "double?"),
  152. new DataType(98, "sql_variant", "object", "object"),
  153. new DataType(99, "ntext", "string", "string"),
  154. new DataType(104, "bit", "bool", "bool?"),
  155. new DataType(106, "decimal", "decimal", "decimal?"),
  156. new DataType(108, "numeric", "decimal", "decimal?"),
  157. //new DataType(122, "smallmoney", "", ""),
  158. new DataType(127, "bigint", "long", "long?"),
  159. //new DataType(240, "hierarchyid", "", ""),
  160. //new DataType(240, "geometry", "", ""),
  161. //new DataType(240, "geography", "", ""),
  162. new DataType(165, "varbinary", "byte[]", "byte[]"),
  163. new DataType(167, "varchar", "string", "string"),
  164. //new DataType(173, "binary", "", ""),
  165. new DataType(175, "char", "string", "string"),
  166. //new DataType(189, "timestamp", "", ""),
  167. new DataType(231, "nvarchar", "string", "string"),
  168. new DataType(239, "nchar", "string", "string"),
  169. new DataType(241, "xml", "string", "string")
  170. //new DataType(231, "sysname", "", "")
  171. };
  172. return types;
  173. }
  174. #region methods to generate source files
  175. private void GenerateDbContext()
  176. {
  177. string indent = string.Empty;
  178. using (FileStream fs = File.Create(string.Format("{0}{1}_Generated.cs", _OutputPath, _DbContextName)))
  179. {
  180. using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
  181. {
  182. // comments
  183. WriteWarnningComments(sw);
  184. // namespace declarations
  185. WriteLine(sw, indent, GetNamespaceDeclarations());
  186. sw.WriteLine();
  187. //namespace
  188. sw.Write("namespace ");
  189. sw.WriteLine(_DefaultNamespace);
  190. // the { for namespace
  191. sw.WriteLine("{");
  192. PushIndent(ref indent);
  193. // class name
  194. WriteLine(sw, indent, string.Format("public partial class {0} : DbContext", _DbContextName));
  195. // the { for class
  196. WriteLine(sw, indent, "{");
  197. PushIndent(ref indent);
  198. // properties
  199. GenerateDbContextProperties(sw, indent);
  200. sw.WriteLine();
  201. // override methods
  202. GenerateDbContextMethods(sw, indent);
  203. PopIndent(ref indent);
  204. // the } for class
  205. WriteLine(sw, indent, "}");
  206. // the } for namespace
  207. PopIndent(ref indent);
  208. WriteLine(sw, indent, "}");
  209. }
  210. }
  211. }
  212. private void GenerateDbContextMethods(StreamWriter sw, string indent)
  213. {
  214. // constructor
  215. /*
  216. * the constructor looks like this:
  217. *
  218. public _DbContactName(string nameOrConnectionString)
  219. : base(nameOrConnectionString)
  220. {
  221. *
  222. * */
  223. WriteLine(sw, indent, string.Format("public {0}(string nameOrConnectionString)", _DbContextName));
  224. PushIndent(ref indent);
  225. WriteLine(sw, indent, ": base(nameOrConnectionString)");
  226. PopIndent(ref indent);
  227. WriteLine(sw, indent, "{");
  228. WriteLine(sw, indent, "}");
  229. sw.WriteLine();
  230. // OnModelCreating method
  231. /*
  232. * The generated OnModelCreating method looks like this:
  233. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  234. {
  235. Configuration.ProxyCreationEnabled = false;
  236. Database.SetInitializer<RcDbContext>(null);
  237. modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
  238. base.OnModelCreating(modelBuilder);
  239. }
  240. */
  241. WriteLine(sw, indent, "protected override void OnModelCreating(DbModelBuilder modelBuilder)");
  242. WriteLine(sw, indent, "{");
  243. PushIndent(ref indent);
  244. WriteLine(sw, indent, string.Format("Database.SetInitializer<{0}>(null);", _DbContextName));
  245. WriteLine(sw, indent, "base.OnModelCreating(modelBuilder);");
  246. WriteLine(sw, indent, "modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();");
  247. WriteLine(sw, indent, "Configuration.ProxyCreationEnabled = false;");
  248. PopIndent(ref indent);
  249. WriteLine(sw, indent, "}");
  250. }
  251. private void GenerateDbContextProperties(StreamWriter sw, string indent)
  252. {
  253. string className, propertyName, statement;
  254. foreach (ListItem item in _SelectedItems)
  255. {
  256. className = GetClassName(item.Value);
  257. if (_PluralizationSvc.IsPlural(className))
  258. {
  259. propertyName = className;
  260. }
  261. else
  262. {
  263. propertyName = _PluralizationSvc.Pluralize(className);
  264. }
  265. statement = string.Format("public DbSet<{0}> {1} {{ get; set; }}", className, propertyName);
  266. WriteLine(sw, indent, statement);
  267. }
  268. }
  269. private void GenerateEntityObject(ListItem objectItem)
  270. {
  271. string objectName = objectItem.Value;
  272. string className = GetClassName(objectName);
  273. string indent = string.Empty;
  274. using (FileStream fs = File.Create(string.Format("{0}{1}_Generated.cs", _OutputPath, className)))
  275. {
  276. using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
  277. {
  278. // comments
  279. WriteWarnningComments(sw);
  280. // namespace declarations
  281. WriteLine(sw, indent, GetNamespaceDeclarations());
  282. sw.WriteLine();
  283. //namespace
  284. sw.Write("namespace ");
  285. sw.WriteLine(_DefaultNamespace);
  286. // the { for namespace
  287. sw.WriteLine("{");
  288. PushIndent(ref indent);
  289. // class name
  290. if (className != objectName)
  291. {
  292. WriteLine(sw, indent, string.Format("[Table(\"{0}\")]", objectName));
  293. }
  294. WriteLine(sw, indent, string.Format("public partial class {0}", className));
  295. // the { for class
  296. WriteLine(sw, indent, "{");
  297. // properties
  298. PushIndent(ref indent);
  299. GenerateProperties(objectName, className, sw, indent);
  300. PopIndent(ref indent);
  301. // the } for class
  302. WriteLine(sw, indent, "}");
  303. // the } for namespace
  304. PopIndent(ref indent);
  305. WriteLine(sw, indent, "}");
  306. }
  307. }
  308. Action addDone = () => lbOutputs.Items.Add(objectName + ": done.");
  309. lbOutputs.Invoke(addDone);
  310. }
  311. private void WriteWarnningComments(StreamWriter sw)
  312. {
  313. sw.WriteLine("/*");
  314. sw.WriteLine(" * The code is generated by code generator.");
  315. sw.WriteLine(" * Do not modify this file. Any modifications will lose when the file is regenerated.");
  316. sw.WriteLine(" * Please extend these entity classes by taking advantage of the partical class feature.");
  317. sw.WriteLine(" */");
  318. sw.WriteLine();
  319. }
  320. private void Write(StreamWriter sw, string indent, string statement)
  321. {
  322. sw.Write(indent);
  323. sw.Write(statement);
  324. }
  325. private void WriteLine(StreamWriter sw, string indent, string statement)
  326. {
  327. sw.Write(indent);
  328. sw.WriteLine(statement);
  329. }
  330. private void GenerateProperties(string tableName, string className, StreamWriter sw, string indent)
  331. {
  332. string strCmd = string.Format(
  333. @"SELECT C.[name] AS ColumnName, C.system_type_id AS DbTypeID, C.is_nullable AS IsNullable, C.max_length AS MaxLength
  334. , EPA.[value] AS AttributeValue, EPD.[value] AS DescriptionValue
  335. , Case When EPP.[value] IS NULL Then
  336. REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(C.[name],'-','_'), '/','_'),'#','Number'),'.','_'),' ','_')
  337. Else EPP.[value] End AS PropertyName, EPL.[value] AS PropertyLabel, EPDT.[value] AS PropertyDataType
  338. FROM sys.columns C
  339. LEFT JOIN sys.extended_properties EPA ON EPA.major_id = C.[object_id] AND EPA.minor_id = C.column_id AND EPA.name IN ('SYN_EFAttribute')
  340. LEFT JOIN sys.extended_properties EPP ON EPP.major_id = C.[object_id] AND EPP.minor_id = C.column_id AND EPP.name IN ('SYN_EFPropertyName')
  341. LEFT JOIN sys.extended_properties EPD ON EPD.major_id = C.[object_id] AND EPD.minor_id = C.column_id AND EPD.name IN ('MS_Description')
  342. LEFT JOIN sys.extended_properties EPL ON EPL.major_id = C.[object_id] AND EPL.minor_id = C.column_id AND EPL.name IN ('SYN_EFPropertyLabel')
  343. LEFT JOIN sys.extended_properties EPDT ON EPDT.major_id = C.[object_id] AND EPDT.minor_id = C.column_id AND EPDT.name IN ('SYN_EFPropertyDataType')
  344. WHERE [object_id] = Object_ID('{0}')
  345. ORDER BY column_id", tableName);
  346. Database db = DatabaseFactory.CreateDatabase();
  347. using (IDataReader reader = db.ExecuteReader(CommandType.Text, strCmd))
  348. {
  349. string propertyName, columnName, attributeValue, descriptionValue, propertyType, propertyLabel, propertyDataType;
  350. int maxLength, dbTypeID;
  351. bool isNullable;
  352. while (reader.Read())
  353. {
  354. columnName = reader["ColumnName"].ToString();
  355. propertyName = reader["PropertyName"].ToString();
  356. dbTypeID = int.Parse(reader["DbTypeID"].ToString());
  357. isNullable = (bool)reader["IsNullable"];
  358. propertyType = GetTypeName(dbTypeID, isNullable);
  359. propertyLabel = reader["PropertyLabel"].ToString();
  360. propertyDataType = reader["PropertyDataType"].ToString();
  361. //if (propertyType == "ERROR")
  362. //{
  363. // MessageBox.Show(string.Format("Cannot get type name for the type id: {0}", dbTypeID));
  364. //}
  365. maxLength = int.Parse(reader["MaxLength"].ToString());
  366. if (string.Compare(propertyName, className + "ID", true) == 0)
  367. {
  368. //WriteLine(sw, indent, string.Format("[Column(\"{0}\")]", columnName));
  369. //propertyName = "Id";
  370. WriteLine(sw, indent, "[Key]");
  371. }
  372. else if (propertyName == className)
  373. propertyName += "Content";
  374. else if (propertyName != columnName)
  375. {
  376. WriteLine(sw, indent, string.Format("[Column(\"{0}\")]", columnName));
  377. }
  378. else if (className.EndsWith("View", StringComparison.CurrentCultureIgnoreCase)
  379. && string.Compare(propertyName, className.Substring(0, className.Length - 4) + "ID", true) == 0)
  380. {
  381. WriteLine(sw, indent, "[Key]");
  382. }
  383. // generate comment
  384. descriptionValue = reader["DescriptionValue"] is DBNull ? null : reader["DescriptionValue"].ToString();
  385. if (!string.IsNullOrEmpty(descriptionValue))
  386. {
  387. WriteLine(sw, indent, "/// <summary>");
  388. WriteLine(sw, indent, "/// " + descriptionValue);
  389. WriteLine(sw, indent, "/// </summary>");
  390. }
  391. // generate attributes
  392. attributeValue = reader["AttributeValue"] is DBNull ? null : reader["AttributeValue"].ToString();
  393. if (!string.IsNullOrEmpty(attributeValue))
  394. {
  395. string[] attributes = attributeValue.Split('|');
  396. foreach (string attr in attributes)
  397. {
  398. WriteLine(sw, indent, string.Format("[{0}]", attr));
  399. }
  400. }
  401. if (propertyType == "string" && maxLength > 0)
  402. WriteLine(sw, indent, string.Format("[StringLength({0})]", maxLength));
  403. if (propertyType.StartsWith("DateTime"))
  404. {
  405. WriteLine(sw, indent, "[DataType(DataType.Date)]");
  406. WriteLine(sw, indent, "[DisplayFormat(DataFormatString = \"{0:d}\", ApplyFormatInEditMode = true)]");
  407. }
  408. if (!isNullable)
  409. {
  410. WriteLine(sw, indent, "[Required]");
  411. }
  412. if (!string.IsNullOrEmpty(propertyLabel))
  413. {
  414. WriteLine(sw, indent, string.Format("[Display(Name = \"{0}\")]", propertyLabel));
  415. }
  416. if (!string.IsNullOrEmpty(propertyDataType))
  417. {
  418. WriteLine(sw, indent, string.Format("[DataType(DataType.{0})]", propertyDataType));
  419. }
  420. // generate property
  421. WriteLine(sw, indent, string.Format("public {0} {1} {{ get; set; }}", propertyType, propertyName));
  422. sw.WriteLine();
  423. }
  424. }
  425. }
  426. private void PushIndent(ref string indent)
  427. {
  428. indent = indent + "\t";
  429. }
  430. private void PopIndent(ref string indent)
  431. {
  432. indent = indent.Substring(1);
  433. }
  434. private string GetNamespaceDeclarations()
  435. {
  436. return @"using System;
  437. using System.Collections.Generic;
  438. using System.Linq;
  439. using System.Text;
  440. using System.ComponentModel.DataAnnotations;
  441. using System.ComponentModel.DataAnnotations.Schema;
  442. using System.Data.Entity;";
  443. }
  444. private string GetClassName(string tableName)
  445. {
  446. string className = tableName;
  447. if (char.IsLower(className[0]))
  448. {
  449. className = string.Format("{0}{1}", char.ToUpper(className[0]), className.Substring(1));
  450. }
  451. if (className.Contains('_'))
  452. {
  453. string[] nameParts = className.Split('_');
  454. if (_PluralizationSvc.IsPlural(nameParts[nameParts.Length - 1]))
  455. nameParts[1] = _PluralizationSvc.Singularize(nameParts[nameParts.Length - 1]);
  456. className = string.Join("_", nameParts);
  457. }
  458. else
  459. {
  460. if (_PluralizationSvc.IsPlural(className))
  461. className = _PluralizationSvc.Singularize(className);
  462. }
  463. if (className.StartsWith("Ref_", StringComparison.CurrentCultureIgnoreCase))
  464. return className.Substring(4);
  465. if (className.StartsWith("vw_", StringComparison.CurrentCultureIgnoreCase))
  466. return className.Substring(3) + "View";
  467. else if (className.StartsWith("vw", StringComparison.CurrentCultureIgnoreCase))
  468. return className.Substring(2) + "View";
  469. return className;
  470. }
  471. #endregion
  472. private void tbTableFilter_TextChanged(object sender, EventArgs e)
  473. {
  474. FilterListItem(clbTables, tbTableFilter.Text);
  475. }
  476. private void tbViewFilter_TextChanged(object sender, EventArgs e)
  477. {
  478. FilterListItem(clbViews, tbViewFilter.Text);
  479. }
  480. private void FilterListItem(CheckedListBox clb, string filter)
  481. {
  482. if (string.IsNullOrEmpty(filter))
  483. return;
  484. ListItem li;
  485. for (int i = 0; i < clb.Items.Count; i++)
  486. {
  487. li = clb.Items[i] as ListItem;
  488. if (li.Value.StartsWith(filter, StringComparison.CurrentCultureIgnoreCase))
  489. {
  490. clb.SetSelected(i, true);
  491. break;
  492. }
  493. }
  494. }
  495. private void tbTableFilter_KeyPress(object sender, KeyPressEventArgs e)
  496. {
  497. if (e.KeyChar == ' ')
  498. {
  499. CheckSelectedListItem(clbTables);
  500. e.Handled = true;
  501. tbTableFilter.Text = string.Empty;
  502. }
  503. }
  504. private void tbViewFilter_KeyPress(object sender, KeyPressEventArgs e)
  505. {
  506. if (e.KeyChar == ' ')
  507. {
  508. CheckSelectedListItem(clbViews);
  509. e.Handled = true;
  510. tbViewFilter.Text = string.Empty;
  511. }
  512. }
  513. private void CheckSelectedListItem(CheckedListBox clb)
  514. {
  515. if (clb.SelectedIndex < 0)
  516. return;
  517. clb.SetItemChecked(clb.SelectedIndex, !clb.GetItemChecked(clb.SelectedIndex));
  518. }
  519. }
  520. }