在昨天一个大学师弟,他问我能不能将LinqToSql文件转化为创建表的TSql语句,他是刚开始学习.NET,所以在网上下些示例看,但苦于没有数据库。所以就有了这一篇博客,作为我的Code生成技术的CodeSimth的最后一篇示例。在下一步Code 生成技术将转到Microsoft的T4模板,Code生成技术目前完成的有CodeDom,CodeSmith模板,高手请不要拍砖,请直接跳过。

     在Linq2Sql的Dbml文件其实就是一个Xml文件,记录着数据库与生成Linq2SqlCode的数据信息,所以转化为TSql没有什么说的。我们需要提取其中的数据库信息,在转化为我们的Tsql,在这里建立了DBTable、DBColumn、DBAssociation三个实体类:代码

  1.  1 using System;   
  2.   2 using System.Collections.Generic;   
  3.   3 using System.Linq;   
  4.   4 using System.Text;   
  5.   5   
  6.   6 namespace DbmlToTable   
  7.   7 {   
  8.   8     public class DBTable   
  9.   9     {   
  10.  10   
  11.  11         public DBTable()   
  12.  12         {   
  13.  13             Columns = new List<DBColumn>();   
  14.  14             this.Associations = new List<DBAssociation>();   
  15.  15         }   
  16.  16   
  17.  17         public string TableName   
  18.  18         {   
  19.  19             get;   
  20.  20             set;   
  21.  21         }   
  22.  22   
  23.  23         public List<DBColumn> Columns   
  24.  24         {   
  25.  25             get;   
  26.  26             set;   
  27.  27         }   
  28.  28   
  29.  29         public List<DBAssociation> Associations   
  30.  30         {   
  31.  31             get;   
  32.  32             set;   
  33.  33         }   
  34.  34   
  35.  35     }   
  36.  36   
  37.  37     public class DBColumn   
  38.  38     {   
  39.  39         public string Name   
  40.  40         {   
  41.  41             get;   
  42.  42             set;   
  43.  43         }   
  44.  44   
  45.  45         public string DBType   
  46.  46         {   
  47.  47             get;   
  48.  48             set;   
  49.  49         }   
  50.  50   
  51.  51         public bool IsPrimaryKey   
  52.  52         {   
  53.  53             get;   
  54.  54             set;   
  55.  55         }   
  56.  56   
  57.  57         public bool IsDbGenerated   
  58.  58         {   
  59.  59             get;   
  60.  60             set;   
  61.  61         }   
  62.  62   
  63.  63         public bool CanBeNull   
  64.  64         {   
  65.  65             get;   
  66.  66             set;   
  67.  67         }   
  68.  68     }   
  69.  69   
  70.  70     public class DBAssociation   
  71.  71     {   
  72.  72         public string Name   
  73.  73         {   
  74.  74             get;   
  75.  75             set;   
  76.  76         }   
  77.  77   
  78.  78         public string ThisKey   
  79.  79         {   
  80.  80             get;   
  81.  81             set;   
  82.  82         }   
  83.  83   
  84.  84         public string OtherKey   
  85.  85         {   
  86.  86             get;   
  87.  87             set;   
  88.  88         }   
  89.  89   
  90.  90         public bool IsForeignKey   
  91.  91         {   
  92.  92             get;   
  93.  93             set;   
  94.  94         }   
  95.  95     }   
  96.  96   
  97.  97     public class DBTableHlper   
  98.  98     {   
  99.  99         public static DBTable GetAssociationTable(List<DBTable> collection,string assName)   
  100. 100         {   
  101. 101   
  102. 102             return collection.Find(t => t.Associations.Find(a => !a.IsForeignKey && a.Name == assName) != null);   
  103. 103         }   
  104. 104     }   
  105. 105 }  
  106. 106   
  107. 107   
  108. 复制代码 

   其中DBTableHlper是由于我的Codesimth是2.0版本的,不能用lamdam表达式,所以我将它编译在程序集里面。

   建立了一个 将我们的dbml文件xml Document转化为实体类辅助类:

  1. 代码   
  2.  
  3.  1 using System;   
  4.  2 using System.Collections.Generic;   
  5.  3 using System.Linq;   
  6.  4 using System.Text;   
  7.  5 using System.Xml;   
  8.  6 using System.Xml.Linq;   
  9.  7   
  10.  8 namespace DbmlToTable   
  11.  9 {   
  12. 10   
  13. 11     public interface IDbTableCollectionHelper   
  14. 12     {   
  15. 13         List<DBTable> Transport(XElement element);   
  16. 14     }   
  17. 15   
  18. 16     public class DbTableCollectionHelper : IDbTableCollectionHelper   
  19. 17     {   
  20. 18         #region IDbTableCollectionHelper 成员   
  21. 19   
  22. 20         public List<DBTable> Transport(XElement element)   
  23. 21         {   
  24. 22             List<DBTable> collection = new List<DBTable>();   
  25. 23             var tables = element.Elements(XName.Get("Table", "http://schemas.microsoft.com/linqtosql/dbml/2007%22));   
  26. 24             foreach (var tab in tables)   
  27. 25             {   
  28. 26                 DBTable t = new DBTable() { TableName = tab.Attribute("Name").Value };   
  29. 27                 var cols = tab.Element(XName.Get("Type""http://schemas.microsoft.com/linqtosql/dbml/2007%22)).Elements(XName.Get(%22Column%22, "http://schemas.microsoft.com/linqtosql/dbml/2007%22));   
  30. 28                 foreach (var col in cols)   
  31. 29                 {   
  32. 30                     DBColumn c = new DBColumn()   
  33. 31                     {   
  34. 32                         CanBeNull = col.Attribute("CanBeNull") != null ? col.Attribute("CanBeNull").Value.ToLower() == "true" : false,   
  35. 33                         DBType = col.Attribute("DbType") != null ? col.Attribute("DbType").Value : "",   
  36. 34                         IsDbGenerated = col.Attribute("IsDbGenerated") != null ? col.Attribute("IsDbGenerated").Value.ToLower() == "true" : false,   
  37. 35                         IsPrimaryKey = col.Attribute("IsPrimaryKey") != null ? col.Attribute("IsPrimaryKey").Value.ToLower() == "true" : false,   
  38. 36                         Name = col.Attribute("Name") != null ? col.Attribute("Name").Value : ""   
  39. 37                     };   
  40. 38                     t.Columns.Add(c);   
  41. 39                 }   
  42. 40   
  43. 41                 var ass = tab.Element(XName.Get("Type""http://schemas.microsoft.com/linqtosql/dbml/2007%22)).Elements(XName.Get(%22Association%22, "http://schemas.microsoft.com/linqtosql/dbml/2007%22));   
  44. 42                 foreach (var item in ass)   
  45. 43                 {   
  46. 44                     DBAssociation a = new DBAssociation()   
  47. 45                     {   
  48. 46                         Name = item.Attribute("Name") != null ? item.Attribute("Name").Value : "",   
  49. 47                         OtherKey = item.Attribute("OtherKey") != null ? item.Attribute("OtherKey").Value : "",   
  50. 48                         ThisKey = item.Attribute("ThisKey") != null ? item.Attribute("ThisKey").Value : "",   
  51. 49                         IsForeignKey = item.Attribute("IsForeignKey") != null ? item.Attribute("IsForeignKey").Value.ToLower() == "true" : false   
  52. 50                     };   
  53. 51                     t.Associations.Add(a);   
  54. 52                 }   
  55. 53                 collection.Add(t);   
  56. 54             }   
  57. 55             return collection;   
  58. 56         }   
  59. 57   
  60. 58         #endregion   
  61. 59     }   
  62. 60 }  
  63. 61   
  64. 62   
  65. 复制代码 

  在转化为我们的实体类,我们剩下的就是编写我们的CodeSmith模板了(更多知识可以参考CodeSmith模板):

  1. 代码   
  2.  
  3.  1 <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %>   
  4.  2   
  5.  3 <%@ Import NameSpace="System" %>   
  6.  4 <%@ Import NameSpace="System.Xml" %>   
  7.  5 <%@ Import NameSpace="System.Text" %>   
  8.  6 <%@ Import NameSpace="System.Collections.Generic" %>   
  9.  7 <%@ Assembly Name="DbmlToTable" %>   
  10.  8   
  11.  9 --Code By Wolf   
  12. 10 <script runat="template">   
  13. 11 private List<DbmlToTable.DBTable> _DbTableCollection;   
  14. 12 public List<DbmlToTable.DBTable> DbTableCollection   
  15. 13 {   
  16. 14     get   
  17. 15     {   
  18. 16         return _DbTableCollection;   
  19. 17     }   
  20. 18     set      
  21. 19     {   
  22. 20         _DbTableCollection=value;   
  23. 21     }   
  24. 22 }   
  25. 23   
  26. 24 public  string GeneratorTableSql(List<DbmlToTable.DBTable> collection)   
  27. 25 {   
  28. 26     StringBuilder sb = new StringBuilder();   
  29. 27     StringBuilder sbAssocation = new StringBuilder();   
  30. 28     foreach (DbmlToTable.DBTable item in collection)   
  31. 29     {   
  32. 30         List<string> cols = new List<string>();   
  33. 31         foreach (DbmlToTable.DBColumn  col in item.Columns)   
  34. 32         {   
  35. 33             cols.Add(string.Format("{0} {1} {2} ", col.Name, col.DBType, col.IsPrimaryKey ? "PRIMARY KEY " : ""));   
  36. 34         }   
  37. 35         sb.AppendFormat("\r\nCREATE TABLE {0} \r\n(\r\n{1}\r\n)", item.TableName, string.Join(",\r\n", cols.ToArray()));   
  38. 36   
  39. 37         foreach (DbmlToTable.DBAssociation ass in item.Associations)   
  40. 38         {   
  41. 39             if (ass.IsForeignKey)   
  42. 40             {   
  43. 41                 DbmlToTable.DBTable tab = DbmlToTable.DBTableHlper.GetAssociationTable(collection,ass.Name);   
  44. 42                 if (tab != null)   
  45. 43                 {   
  46. 44                     sbAssocation.AppendLine();   
  47. 45                     sbAssocation.AppendFormat(@"ALTER TABLE {0}  WITH NOCHECK ADD  CONSTRAINT {1} FOREIGN KEY({2}) REFERENCES {3} ({4})",   
  48. 46                         item.TableName, "FK_" + ass.Name, ass.ThisKey, tab.TableName, ass.OtherKey);   
  49. 47                 }   
  50. 48             }   
  51. 49         }   
  52. 50     }   
  53. 51   
  54. 52     return sb.ToString() + "\r\n" + sbAssocation.ToString();   
  55. 53 }   
  56. 54 </script>   
  57. 55 <%= this.GeneratorTableSql(_DbTableCollection) %>  
  58. 56   
  59. 57   
  60. 复制代码 

在codeSimth中我们建立了一个集合属性传递实体类DBTable和一个转化TSql辅助方法.

      在控制台调用编译模板以及输出:

  1. 代码   
  2.  1 <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %>   
  3.  2   
  4.  3 <%@ Import NameSpace="System" %>   
  5.  4 <%@ Import NameSpace="System.Xml" %>   
  6.  5 <%@ Import NameSpace="System.Text" %>   
  7.  6 <%@ Import NameSpace="System.Collections.Generic" %>   
  8.  7 <%@ Assembly Name="DbmlToTable" %>   
  9.  8   
  10.  9 --Code By Wolf   
  11. 10 <script runat="template">   
  12. 11 private List<DbmlToTable.DBTable> _DbTableCollection;   
  13. 12 public List<DbmlToTable.DBTable> DbTableCollection   
  14. 13 {   
  15. 14     get   
  16. 15     {   
  17. 16         return _DbTableCollection;   
  18. 17     }   
  19. 18     set      
  20. 19     {   
  21. 20         _DbTableCollection=value;   
  22. 21     }   
  23. 22 }   
  24. 23   
  25. 24 public  string GeneratorTableSql(List<DbmlToTable.DBTable> collection)   
  26. 25 {   
  27. 26     StringBuilder sb = new StringBuilder();   
  28. 27     StringBuilder sbAssocation = new StringBuilder();   
  29. 28     foreach (DbmlToTable.DBTable item in collection)   
  30. 29     {   
  31. 30         List<string> cols = new List<string>();   
  32. 31         foreach (DbmlToTable.DBColumn  col in item.Columns)   
  33. 32         {   
  34. 33             cols.Add(string.Format("{0} {1} {2} ", col.Name, col.DBType, col.IsPrimaryKey ? "PRIMARY KEY " : ""));   
  35. 34         }   
  36. 35         sb.AppendFormat("\r\nCREATE TABLE {0} \r\n(\r\n{1}\r\n)", item.TableName, string.Join(",\r\n", cols.ToArray()));   
  37. 36   
  38. 37         foreach (DbmlToTable.DBAssociation ass in item.Associations)   
  39. 38         {   
  40. 39             if (ass.IsForeignKey)   
  41. 40             {   
  42. 41                 DbmlToTable.DBTable tab = DbmlToTable.DBTableHlper.GetAssociationTable(collection,ass.Name);   
  43. 42                 if (tab != null)   
  44. 43                 {   
  45. 44                     sbAssocation.AppendLine();   
  46. 45                     sbAssocation.AppendFormat(@"ALTER TABLE {0}  WITH NOCHECK ADD  CONSTRAINT {1} FOREIGN KEY({2}) REFERENCES {3} ({4})",   
  47. 46                         item.TableName, "FK_" + ass.Name, ass.ThisKey, tab.TableName, ass.OtherKey);   
  48. 47                 }   
  49. 48             }   
  50. 49         }   
  51. 50     }   
  52. 51   
  53. 52     return sb.ToString() + "\r\n" + sbAssocation.ToString();   
  54. 53 }   
  55. 54 </script>   
  56. 55 <%= this.GeneratorTableSql(_DbTableCollection) %>  
  57. 56   
  58. 57   
  59. 复制代码  

   在CodeSimth中就是这么简单,生成相应的模板代码(个人理解CodeSmith就是把代码作为字符串输出)。

在上面到我的CodeSmith模板编译辅助类,在上一篇通过代码生成机制实现强类型编程-CodeSmith版也有,在这里也附带上:需要引用CodeSmith.Engine.dll.

  1. 代码   
  2.  
  3.  1 using System;   
  4.  2   
  5.  3 using System.Collections.Generic;   
  6.  4   
  7.  5 using System.Linq;   
  8.  6   
  9.  7 using System.Text;   
  10.  8   
  11.  9 using CodeSmith.Engine;   
  12. 10   
  13. 11 using Wolf.NameValueDictionary;   
  14. 12   
  15. 13 namespace DbmlToTable   
  16. 14   
  17. 15 {   
  18. 16   
  19. 17 public class CodeSimthTemplateHelper   
  20. 18   
  21. 19 {   
  22. 20   
  23. 21      public static CodeTemplate CompileTemplate(string templateName, Action errorWriter)   
  24. 22   
  25. 23      {   
  26. 24   
  27. 25            CodeTemplateCompiler compiler = new CodeTemplateCompiler(templateName); compiler.Compile();   
  28. 26   
  29. 27           if (compiler.Errors.Count == 0)   
  30. 28   
  31. 29            {   
  32. 30   
  33. 31            return compiler.CreateInstance();  
  34. 32   
  35. 33            }   
  36. 34   
  37. 35        else   
  38. 36   
  39. 37          {   
  40. 38   
  41. 39            for (int i = 0; i < compiler.Errors.Count; i++)   
  42. 40   
  43. 41         {   
  44. 42   
  45. 43             errorWriter(compiler.Errors[i].ToString());   
  46. 44   
  47. 45          }   
  48. 46   
  49. 47         return null;   
  50. 48   
  51. 49        }   
  52. 50   
  53. 51 }   
  54. 52   
  55. 53    
  56. 54   
  57. 55 public static void AddPropertyParams(CodeTemplate template,object param)   
  58. 56   
  59. 57 {   
  60. 58   
  61. 59       NameValueDictionary dict = new NameValueDictionary<object>(param);  
  62. 60   
  63. 61        AddPropertyParams(template, dict);  
  64. 62   
  65. 63 }  
  66. 64   
  67. 65    
  68. 66   
  69. 67 public static void AddPropertyParams(CodeTemplate template, NameValueDictionary<object> param)  
  70. 68   
  71. 69 {  
  72. 70   
  73. 71           NameValueDictionary<object> dict = new NameValueDictionary<object>(param);  
  74. 72   
  75. 73           foreach (var item in dict.Keys)  
  76. 74   
  77. 75           {  
  78. 76   
  79. 77                 template.SetProperty(item, dict[item]);  
  80. 78   
  81. 79            }  
  82. 80   
  83. 81 }  
  84. 82   
  85. 83 }  
  86. 84   
  87. 85 }  
  88. 86   
  89. 复制代码