在昨天一个大学师弟,他问我能不能将LinqToSql文件转化为创建表的TSql语句,他是刚开始学习.NET,所以在网上下些示例看,但苦于没有数据库。所以就有了这一篇博客,作为我的Code生成技术的CodeSimth的最后一篇示例。在下一步Code 生成技术将转到Microsoft的T4模板,Code生成技术目前完成的有CodeDom,CodeSmith模板,高手请不要拍砖,请直接跳过。
在Linq2Sql的Dbml文件其实就是一个Xml文件,记录着数据库与生成Linq2SqlCode的数据信息,所以转化为TSql没有什么说的。我们需要提取其中的数据库信息,在转化为我们的Tsql,在这里建立了DBTable、DBColumn、DBAssociation三个实体类:代码
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Linq;
- 4 using System.Text;
- 5
- 6 namespace DbmlToTable
- 7 {
- 8 public class DBTable
- 9 {
- 10
- 11 public DBTable()
- 12 {
- 13 Columns = new List<DBColumn>();
- 14 this.Associations = new List<DBAssociation>();
- 15 }
- 16
- 17 public string TableName
- 18 {
- 19 get;
- 20 set;
- 21 }
- 22
- 23 public List<DBColumn> Columns
- 24 {
- 25 get;
- 26 set;
- 27 }
- 28
- 29 public List<DBAssociation> Associations
- 30 {
- 31 get;
- 32 set;
- 33 }
- 34
- 35 }
- 36
- 37 public class DBColumn
- 38 {
- 39 public string Name
- 40 {
- 41 get;
- 42 set;
- 43 }
- 44
- 45 public string DBType
- 46 {
- 47 get;
- 48 set;
- 49 }
- 50
- 51 public bool IsPrimaryKey
- 52 {
- 53 get;
- 54 set;
- 55 }
- 56
- 57 public bool IsDbGenerated
- 58 {
- 59 get;
- 60 set;
- 61 }
- 62
- 63 public bool CanBeNull
- 64 {
- 65 get;
- 66 set;
- 67 }
- 68 }
- 69
- 70 public class DBAssociation
- 71 {
- 72 public string Name
- 73 {
- 74 get;
- 75 set;
- 76 }
- 77
- 78 public string ThisKey
- 79 {
- 80 get;
- 81 set;
- 82 }
- 83
- 84 public string OtherKey
- 85 {
- 86 get;
- 87 set;
- 88 }
- 89
- 90 public bool IsForeignKey
- 91 {
- 92 get;
- 93 set;
- 94 }
- 95 }
- 96
- 97 public class DBTableHlper
- 98 {
- 99 public static DBTable GetAssociationTable(List<DBTable> collection,string assName)
- 100 {
- 101
- 102 return collection.Find(t => t.Associations.Find(a => !a.IsForeignKey && a.Name == assName) != null);
- 103 }
- 104 }
- 105 }
- 106
- 107
- 复制代码
其中DBTableHlper是由于我的Codesimth是2.0版本的,不能用lamdam表达式,所以我将它编译在程序集里面。
建立了一个 将我们的dbml文件xml Document转化为实体类辅助类:
- 代码
- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Linq;
- 4 using System.Text;
- 5 using System.Xml;
- 6 using System.Xml.Linq;
- 7
- 8 namespace DbmlToTable
- 9 {
- 10
- 11 public interface IDbTableCollectionHelper
- 12 {
- 13 List<DBTable> Transport(XElement element);
- 14 }
- 15
- 16 public class DbTableCollectionHelper : IDbTableCollectionHelper
- 17 {
- 18 #region IDbTableCollectionHelper 成员
- 19
- 20 public List<DBTable> Transport(XElement element)
- 21 {
- 22 List<DBTable> collection = new List<DBTable>();
- 23 var tables = element.Elements(XName.Get("Table", "http://schemas.microsoft.com/linqtosql/dbml/2007%22));
- 24 foreach (var tab in tables)
- 25 {
- 26 DBTable t = new DBTable() { TableName = tab.Attribute("Name").Value };
- 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));
- 28 foreach (var col in cols)
- 29 {
- 30 DBColumn c = new DBColumn()
- 31 {
- 32 CanBeNull = col.Attribute("CanBeNull") != null ? col.Attribute("CanBeNull").Value.ToLower() == "true" : false,
- 33 DBType = col.Attribute("DbType") != null ? col.Attribute("DbType").Value : "",
- 34 IsDbGenerated = col.Attribute("IsDbGenerated") != null ? col.Attribute("IsDbGenerated").Value.ToLower() == "true" : false,
- 35 IsPrimaryKey = col.Attribute("IsPrimaryKey") != null ? col.Attribute("IsPrimaryKey").Value.ToLower() == "true" : false,
- 36 Name = col.Attribute("Name") != null ? col.Attribute("Name").Value : ""
- 37 };
- 38 t.Columns.Add(c);
- 39 }
- 40
- 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));
- 42 foreach (var item in ass)
- 43 {
- 44 DBAssociation a = new DBAssociation()
- 45 {
- 46 Name = item.Attribute("Name") != null ? item.Attribute("Name").Value : "",
- 47 OtherKey = item.Attribute("OtherKey") != null ? item.Attribute("OtherKey").Value : "",
- 48 ThisKey = item.Attribute("ThisKey") != null ? item.Attribute("ThisKey").Value : "",
- 49 IsForeignKey = item.Attribute("IsForeignKey") != null ? item.Attribute("IsForeignKey").Value.ToLower() == "true" : false
- 50 };
- 51 t.Associations.Add(a);
- 52 }
- 53 collection.Add(t);
- 54 }
- 55 return collection;
- 56 }
- 57
- 58 #endregion
- 59 }
- 60 }
- 61
- 62
- 复制代码
在转化为我们的实体类,我们剩下的就是编写我们的CodeSmith模板了(更多知识可以参考CodeSmith模板):
- 代码
- 1 <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %>
- 2
- 3 <%@ Import NameSpace="System" %>
- 4 <%@ Import NameSpace="System.Xml" %>
- 5 <%@ Import NameSpace="System.Text" %>
- 6 <%@ Import NameSpace="System.Collections.Generic" %>
- 7 <%@ Assembly Name="DbmlToTable" %>
- 8
- 9 --Code By Wolf
- 10 <script runat="template">
- 11 private List<DbmlToTable.DBTable> _DbTableCollection;
- 12 public List<DbmlToTable.DBTable> DbTableCollection
- 13 {
- 14 get
- 15 {
- 16 return _DbTableCollection;
- 17 }
- 18 set
- 19 {
- 20 _DbTableCollection=value;
- 21 }
- 22 }
- 23
- 24 public string GeneratorTableSql(List<DbmlToTable.DBTable> collection)
- 25 {
- 26 StringBuilder sb = new StringBuilder();
- 27 StringBuilder sbAssocation = new StringBuilder();
- 28 foreach (DbmlToTable.DBTable item in collection)
- 29 {
- 30 List<string> cols = new List<string>();
- 31 foreach (DbmlToTable.DBColumn col in item.Columns)
- 32 {
- 33 cols.Add(string.Format("{0} {1} {2} ", col.Name, col.DBType, col.IsPrimaryKey ? "PRIMARY KEY " : ""));
- 34 }
- 35 sb.AppendFormat("\r\nCREATE TABLE {0} \r\n(\r\n{1}\r\n)", item.TableName, string.Join(",\r\n", cols.ToArray()));
- 36
- 37 foreach (DbmlToTable.DBAssociation ass in item.Associations)
- 38 {
- 39 if (ass.IsForeignKey)
- 40 {
- 41 DbmlToTable.DBTable tab = DbmlToTable.DBTableHlper.GetAssociationTable(collection,ass.Name);
- 42 if (tab != null)
- 43 {
- 44 sbAssocation.AppendLine();
- 45 sbAssocation.AppendFormat(@"ALTER TABLE {0} WITH NOCHECK ADD CONSTRAINT {1} FOREIGN KEY({2}) REFERENCES {3} ({4})",
- 46 item.TableName, "FK_" + ass.Name, ass.ThisKey, tab.TableName, ass.OtherKey);
- 47 }
- 48 }
- 49 }
- 50 }
- 51
- 52 return sb.ToString() + "\r\n" + sbAssocation.ToString();
- 53 }
- 54 </script>
- 55 <%= this.GeneratorTableSql(_DbTableCollection) %>
- 56
- 57
- 复制代码
在codeSimth中我们建立了一个集合属性传递实体类DBTable和一个转化TSql辅助方法.
在控制台调用编译模板以及输出:
- 代码
- 1 <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %>
- 2
- 3 <%@ Import NameSpace="System" %>
- 4 <%@ Import NameSpace="System.Xml" %>
- 5 <%@ Import NameSpace="System.Text" %>
- 6 <%@ Import NameSpace="System.Collections.Generic" %>
- 7 <%@ Assembly Name="DbmlToTable" %>
- 8
- 9 --Code By Wolf
- 10 <script runat="template">
- 11 private List<DbmlToTable.DBTable> _DbTableCollection;
- 12 public List<DbmlToTable.DBTable> DbTableCollection
- 13 {
- 14 get
- 15 {
- 16 return _DbTableCollection;
- 17 }
- 18 set
- 19 {
- 20 _DbTableCollection=value;
- 21 }
- 22 }
- 23
- 24 public string GeneratorTableSql(List<DbmlToTable.DBTable> collection)
- 25 {
- 26 StringBuilder sb = new StringBuilder();
- 27 StringBuilder sbAssocation = new StringBuilder();
- 28 foreach (DbmlToTable.DBTable item in collection)
- 29 {
- 30 List<string> cols = new List<string>();
- 31 foreach (DbmlToTable.DBColumn col in item.Columns)
- 32 {
- 33 cols.Add(string.Format("{0} {1} {2} ", col.Name, col.DBType, col.IsPrimaryKey ? "PRIMARY KEY " : ""));
- 34 }
- 35 sb.AppendFormat("\r\nCREATE TABLE {0} \r\n(\r\n{1}\r\n)", item.TableName, string.Join(",\r\n", cols.ToArray()));
- 36
- 37 foreach (DbmlToTable.DBAssociation ass in item.Associations)
- 38 {
- 39 if (ass.IsForeignKey)
- 40 {
- 41 DbmlToTable.DBTable tab = DbmlToTable.DBTableHlper.GetAssociationTable(collection,ass.Name);
- 42 if (tab != null)
- 43 {
- 44 sbAssocation.AppendLine();
- 45 sbAssocation.AppendFormat(@"ALTER TABLE {0} WITH NOCHECK ADD CONSTRAINT {1} FOREIGN KEY({2}) REFERENCES {3} ({4})",
- 46 item.TableName, "FK_" + ass.Name, ass.ThisKey, tab.TableName, ass.OtherKey);
- 47 }
- 48 }
- 49 }
- 50 }
- 51
- 52 return sb.ToString() + "\r\n" + sbAssocation.ToString();
- 53 }
- 54 </script>
- 55 <%= this.GeneratorTableSql(_DbTableCollection) %>
- 56
- 57
- 复制代码
在CodeSimth中就是这么简单,生成相应的模板代码(个人理解CodeSmith就是把代码作为字符串输出)。
在上面到我的CodeSmith模板编译辅助类,在上一篇通过代码生成机制实现强类型编程-CodeSmith版也有,在这里也附带上:需要引用CodeSmith.Engine.dll.
- 代码
- 1 using System;
- 2
- 3 using System.Collections.Generic;
- 4
- 5 using System.Linq;
- 6
- 7 using System.Text;
- 8
- 9 using CodeSmith.Engine;
- 10
- 11 using Wolf.NameValueDictionary;
- 12
- 13 namespace DbmlToTable
- 14
- 15 {
- 16
- 17 public class CodeSimthTemplateHelper
- 18
- 19 {
- 20
- 21 public static CodeTemplate CompileTemplate(string templateName, Action errorWriter)
- 22
- 23 {
- 24
- 25 CodeTemplateCompiler compiler = new CodeTemplateCompiler(templateName); compiler.Compile();
- 26
- 27 if (compiler.Errors.Count == 0)
- 28
- 29 {
- 30
- 31 return compiler.CreateInstance();
- 32
- 33 }
- 34
- 35 else
- 36
- 37 {
- 38
- 39 for (int i = 0; i < compiler.Errors.Count; i++)
- 40
- 41 {
- 42
- 43 errorWriter(compiler.Errors[i].ToString());
- 44
- 45 }
- 46
- 47 return null;
- 48
- 49 }
- 50
- 51 }
- 52
- 53
- 54
- 55 public static void AddPropertyParams(CodeTemplate template,object param)
- 56
- 57 {
- 58
- 59 NameValueDictionary dict = new NameValueDictionary<object>(param);
- 60
- 61 AddPropertyParams(template, dict);
- 62
- 63 }
- 64
- 65
- 66
- 67 public static void AddPropertyParams(CodeTemplate template, NameValueDictionary<object> param)
- 68
- 69 {
- 70
- 71 NameValueDictionary<object> dict = new NameValueDictionary<object>(param);
- 72
- 73 foreach (var item in dict.Keys)
- 74
- 75 {
- 76
- 77 template.SetProperty(item, dict[item]);
- 78
- 79 }
- 80
- 81 }
- 82
- 83 }
- 84
- 85 }
- 86
- 复制代码
本文转自 破狼 51CTO博客,原文链接:http://blog.51cto.com/whitewolfblog/834728,如需转载请自行联系原作者