小程序大智慧,sqlserver 註釋提取工具

開篇背景

我習慣在寫表的建立腳本時將註釋直接寫在腳本里,好比正則表達式

/*帳套*/
CREATE TABLE [dbo].[AccountingBook]
(
	[IDNO]			NVARCHAR (255) NOT NULL,	/*ID*/
    [BH]			NVARCHAR (255) NULL,		/*業務編號*/
	[Name]			NVARCHAR (255) NOT NULL,	/*名稱*/
	[Decription]	NVARCHAR (255) NULL,		/*描述*/
	[Owner]			NVARCHAR (255) NOT NULL,	/*所屬*/
	CONSTRAINT [PK_AccountingBook] PRIMARY KEY CLUSTERED ([IDNO] ASC)
)

這樣寫很直觀,若是在vs裏建立一個數據庫項目,把表的建立腳本放在裏面進行管理,就很是方便的。sql

因爲習慣用本身的Orm框架,因此DTO也就是那些數據映射實體我都是用codeSmith生成,生成這些DTO對象時,我想共用個人那些註釋,那麼我該怎麼辦呢,以前,我須要把這些註釋複製出來寫成一些註釋建立的腳本,像這樣  數據庫

exec sp_addextendedproperty N'MS_Description', N'字段描述', N'user', N'dbo', N'table', N'表名', N'column', N'字段名'

添加註釋的目的是除了在使用數據庫鏈接工具時方便查看錶和字段的說明外,還可使用CodeSmith生成代碼的時候就能夠經過編寫模版生成帶註釋的映射DTO 對象,以下  框架

/// <summary>
/// 業務編號
/// </summary>
[Column(ColumnName=Columns.BH,FullName=Columns.BHFullName,Index=1,CType=typeof(string),Description="業務編號")]
[DataMember(Order = 1)]
public virtual string BH{get;set;}

可是因爲表建立腳本里的註釋不能直接寫入到數據庫的表和字段中,因此註釋的建立腳本我須要再寫一次,我以爲比較不爽,因而我決定寫個小工具從表的建立腳本里面抽取那些原本就寫好的註釋,從而減少重複機械的工做,也防止錯誤的發生。ide

這樣一個程序很是簡單,下面說一下思路工具

實現

一,寫好帶註釋的表腳本,並提取這些信息

格式按文章開始講到的那樣寫好,即"/*註釋*/",「*」能夠是多個,好比"/*********註釋***********/",並將這些腳本存放到相同根目錄ui

要提取這些註釋,最大的功臣非正則表達式莫屬了this

    

a.提取表頭的註釋,也就是表名的解釋正則表達式      spa

 private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");

b.提取列的註釋正則表達式code

private readonly Regex _columnsReg = new Regex(@"\[([\w]*)\][^\/]*/[\*]+([^\*]*)[\*]+/");

二,遞歸查找到這些表的建立腳本,將每一個生成註釋腳本的字符串鏈接起來

Func<string, List<string>> getFolderSqlNotes = null;
    getFolderSqlNotes = path =>
    {
        var listAll = new List<string>();
        var files = Directory.GetFiles(path);
        var dirs = Directory.GetDirectories(path);
        foreach (string t in dirs)
        {
            listAll.AddRange(getFolderSqlNotes(t)); ;
        }
        var listStr = files.Where(m => m.EndsWith(".sql")).Select(GetDescriptionSql).ToList();
        listAll.AddRange(listStr);
        return listAll;
    };
    var list = getFolderSqlNotes(Path);
    return string.Join("\r\n", list);

三,執行生成好的腳本(以下圖),註釋建立完成

四,用codesimth 生成映射類(已帶註釋)

核心代碼

 1 namespace GenrerateSqlDescription
 2 {
 3     using System;
 4     using System.Collections.Generic;
 5     using System.IO;
 6     using System.Linq;
 7     using System.Text;
 8     using System.Text.RegularExpressions;
 9 
10 
11     public class SqlNotesGenerator
12     {
13         private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");
14         private readonly Regex _columnsReg = new Regex(@"\[([\w]*)\][^\/]*/[\*]+([^\*]*)[\*]+/");
15         private const string TableDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user ',dbo,'table',[{1}];\r\n";
16         private const string ColumnDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user',dbo,'table',[{1}],'column','{2}';\r\n";
17         private const string TableDescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}];\r\n";
18         private const string ColumnescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}],'column','{1}';\r\n";
19         private const string CheckTableExistsSqlFormat = "IF OBJECT_ID(N'{0}',N'U') IS NOT NULL \r\nBEGIN \r\n";
20         private const string EndStr = "END";
21         private const string Tab = "    ";
22 
23         public bool GenDrop { get; set; }
24         public string Path { get; set; }
25 
26         private string GetDescriptionSql(string path)
27         {
28             var sb = new StringBuilder();
29             var fs = File.OpenRead(path);
30             var fileRd = new StreamReader(fs);
31             var str = fileRd.ReadToEnd();
32             var tableMatch = _tableReg.Match(str);
33             if (tableMatch.Length < 2) return string.Empty;
34 
35             var tableName = tableMatch.Groups[2].Value;
36             var tableDes = tableMatch.Groups[1].Value;
37             if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(tableDes)) return string.Empty;
38 
39             var columnStr = str.Substring(str.IndexOf("(", StringComparison.Ordinal));
40             var matches = _columnsReg.Matches(columnStr);
41 
42             sb.AppendFormat(CheckTableExistsSqlFormat, tableName);
43 
44             sb.Append(Tab);
45             if (GenDrop)
46                 sb.AppendFormat(TableDescriptionDropSqlFormat, tableName);
47             else
48                 sb.AppendFormat(TableDescriptionCrateSqlFormat, tableDes, tableName);
49             foreach (Match match in matches)
50             {
51                 var columnName = match.Groups[1].Value;
52                 var description = match.Groups[2].Value;
53                 if (string.IsNullOrEmpty(columnName) || string.IsNullOrEmpty(description))
54                     continue;
55                 sb.Append(Tab);
56                 if (GenDrop)
57                     sb.AppendFormat(ColumnescriptionDropSqlFormat, tableName, columnName);
58                 else
59                     sb.AppendFormat(ColumnDescriptionCrateSqlFormat, description, tableName, columnName);
60             }
61 
62             sb.AppendLine(EndStr);
63             return sb.ToString();
64         }
65 
66 
67         public string GetGenerateSql()
68         {
69             Func<string, List<string>> getFolderSqlNotes = null;
70             getFolderSqlNotes = path =>
71             {
72                 var listAll = new List<string>();
73                 var files = Directory.GetFiles(path);
74                 var dirs = Directory.GetDirectories(path);
75                 foreach (string t in dirs)
76                 {
77                     listAll.AddRange(getFolderSqlNotes(t)); ;
78                 }
79                 var listStr = files.Where(m => m.EndsWith(".sql")).Select(GetDescriptionSql).ToList();
80                 listAll.AddRange(listStr);
81                 return listAll;
82             };
83             var list = getFolderSqlNotes(Path);
84             return string.Join("\r\n", list);
85         }
86 
87     }
88 
89 }
SqlNotesGenerator

CodeSimith模版

  1 <%-- 
  2 Name:
  3 Author: 
  4 Description: 
  5 --%>
  6 <%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="" Inherits="OutputFileCodeTemplate" Debug="False" Description="Template description here." %>
  7 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema"  Category="Context"  Optional="True" Description="the table name"   %>
  8 <%@ Assembly Name="SchemaExplorer" %>
  9 <%@ Import Namespace="SchemaExplorer" %>
 10 <%@ Assembly Name="CodeSmith.BaseTemplates" %>
 11 <%@ Import Namespace="CodeSmith.BaseTemplates" %>
 12 <%@ Assembly Name="CodeSmith.CustomProperties" %>
 13 <%@ Import Namespace="CodeSmith.CustomProperties" %>
 14 //------------------------------------------------------------------------------
 15 // <auto-generated>
 16 //     This code generated by the tool, do not propose to amend
 17 //       Generation time:<%=DateTime.Now%>
 18 // </auto-generated>
 19 //------------------------------------------------------------------------------
 20 using System;
 21 using System.Data;
 22 using System.Runtime.Serialization;
 23 using XDbFramework;
 24 using BPM_M01.DataAccessLayer.Base;
 25 using System.Xml.Serialization;
 26 using System.Diagnostics;
 27 using System.CodeDom.Compiler;
 28 
 29 namespace <%=Namespace%>
 30 {
 31     [Table(TableName = <%=this.SourceTable.Name%>.Table.Name ,Descripton = "<%=this.SourceTable.Description%>",GenreratePK = <%=GenreratePK.ToString().ToLower()%>)]
 32       [GeneratedCodeAttribute("System.Xml", "2.0.50727.4927")]
 33     [DebuggerStepThroughAttribute()]
 34     public partial class <%=this.SourceTable.Name%> : DtoBase
 35     {
 36         public static class Table
 37         {
 38             public const string Name = "<%=this.SourceTable.Name%>";
 39         }
 40         public static class Columns
 41         {
 42         <%for(int i=0; i<this.SourceTable.Columns.Count;i++)
 43         {
 44             string colName=this.SourceTable.Columns[i].Name;%>
 45             public const string <%=colName%> = "<%=colName%>";
 46             public const string <%=colName%>FullName =Table.Name + "." + "<%=colName%>";            
 47         <%}%>
 48         }
 49         
 50     <%for(int i=0; i<this.SourceTable.Columns.Count;i++)
 51     {                   
 52         int namelength=this.SourceTable.Columns[i].Name.Length;
 53         string colName=this.SourceTable.Columns[i].Name;
 54         if(colName == "ID" || colName == "IDNO") continue;
 55         string titleCaseColumName = colName.Substring(0,1).ToUpper() + colName.Substring(1,colName.Length-1);
 56         %>
 57         
 58         /// <summary>
 59         /// <%=this.SourceTable.Columns[i].Description%>
 60         /// </summary>
 61         <%if(this.SourceTable.Columns[i].IsPrimaryKeyMember){%>
 62         [Column(KeyType = KeyTypeEnum.PrimaryKey,FullName="<%=this.SourceTable.Name%>.<%=this.SourceTable.Columns[i].Name%>", ColumnName="<%=this.SourceTable.Columns[i].Name%>",Index=<%=i%>,Description="<%=this.SourceTable.Columns[i].Description%>")]
 63         <%}%>
 64         <%else{%>
 65         <%if(this.SourceTable.Columns[i].IsForeignKeyMember)%>
 66         <%// 
 67         foreach(TableKeySchema tks in SourceTable.ForeignKeys)
 68         {
 69         // 
 70             
 71             foreach(MemberColumnSchema mcs in tks.ForeignKeyMemberColumns)
 72             {
 73                 
 74                 // 
 75                 if(mcs.Name == SourceTable.Columns[i].Name)
 76                 {
 77                     TableSchema ts= tks.PrimaryKeyTable;%>
 78         [Column(ColumnName=Columns.<%=colName%>,KeyType = KeyTypeEnum.ForeignKey,FullName=Columns.<%=colName%>FullName,CType=typeof(<%=GetCSharpVariableType(this.SourceTable.Columns[i])%>),ForeignKeyTableName="<%=ts.Name%>",ForeignKeyFiledName="<%=ts.PrimaryKey.MemberColumns[0].Name%>", DbType=<%=GetSqlDBType(this.SourceTable.Columns[i].NativeType)%> Index=<%=i%>,Description="<%=this.SourceTable.Columns[i].Description%>")]
 79                    <% break;
 80                 }
 81             }
 82         }
 83         %>
 84         <%else{%>
 85         [Column(ColumnName=Columns.<%=colName%>,FullName=Columns.<%=colName%>FullName,Index=<%=i%>,CType=typeof(<%=GetCSharpVariableType(this.SourceTable.Columns[i])%>),Description="<%=this.SourceTable.Columns[i].Description%>")]
 86         <%}%>
 87         <%}%>
 88         [DataMember(Order = <%=i%>)]
 89         public virtual <%=GetCSharpVariableType(this.SourceTable.Columns[i])%> <%=titleCaseColumName%>{get;set;}
 90     
 91     <%}%>        
 92     }    
 93 }
 94 
 95 <script runat="template">
 96 // Override the OutputFile property and assign our specific settings to it.
 97 [FileDialog(FileDialogType.Save, Title="Select Output File", Filter="C# Files (*.cs)|*.cs", DefaultExtension=".cs")]
 98 public override string OutputFile
 99 {
100     get {return base.OutputFile;}
101     set {base.OutputFile = value;}
102 }
103 private string _Namespace;
104 public string Namespace
105 {
106     get{return _Namespace;}    
107     set{_Namespace = value;}
108 }
109 
110 public bool GenreratePK{get;set;}
111 </script>
112 <script runat="template">
113 public string GetSqlDBType(string type)
114 {
115     switch(type)
116     {
117         case "int": return "SqlDbType.Int,";
118         case "bit": return "SqlDbType.Bit,";
119         case "bigint": return "SqlDbType.BigInt,";
120         case "tinyint": return "SqlDbType.TinyInt,";
121         case "nvarchar": return "SqlDbType.NVarChar,";
122         case "date": return "SqlDbType.Date,";
123         case "datetime": return "SqlDbType.DateTime,";
124         case "char": return "SqlDbType.Char,";
125         case "decimal": return "SqlDbType.Decimal,";
126         case "float": return "SqlDbType.Float,";
127         case "image": return "SqlDbType.Image,";
128         case "money": return "SqlDbType.Money,";
129         case "nchar": return "SqlDbType.NChar,";
130         case "ntext": return "SqlDbType.NText,";
131         case "real": return "SqlDbType.Real,";
132         case "smalldatetime": return "SqlDbType.SmallDateTime,";
133         case "smallint": return "SqlDbType.SmallInt,";
134         case "smallmoney": return "SqlDbType.SmallMoney,";
135         case "text": return "SqlDbType.Text,";
136         case "timestamp": return "SqlDbType.Timestamp,";
137         case "udt": return "SqlDbType.Udt,";
138         case "uniqueidentifier": return "SqlDbType.UniqueIdentifier,";
139         case "varbinary": return "SqlDbType.VarBinary,";
140         case "varchar": return "SqlDbType.VarChar,";
141         case "variant": return "SqlDbType.Variant,";
142         case "xml": return "SqlDbType.Xml,";
143         default : return "";
144     }
145     
146 }
147 public string GetCSharpVariableType(ColumnSchema column)
148 {
149     switch (column.DataType)
150     {
151         case DbType.AnsiString: return "string";
152         case DbType.AnsiStringFixedLength: return "string";
153         case DbType.Binary: return "byte[]";
154         case DbType.Boolean: return "bool?";
155         case DbType.Byte: return "byte";
156         case DbType.Currency: return "decimal?";
157         case DbType.Date: return "DateTime?";
158         case DbType.DateTime: return "DateTime?";
159         case DbType.Decimal: return "decimal?";
160         case DbType.Double: return "double?";
161         case DbType.Guid: return "Guid";
162         case DbType.Int16: return "short?";
163         case DbType.Int32: return "int?";
164         case DbType.Int64: return "long?";
165         case DbType.Object: return "object";
166         case DbType.SByte: return "sbyte";
167         case DbType.Single: return "float?";
168         case DbType.String: return "string";
169         case DbType.StringFixedLength: return "string";
170         case DbType.Time: return "TimeSpan";
171         case DbType.UInt16: return "ushort?";
172         case DbType.UInt32: return "uint?";
173         case DbType.UInt64: return "ulong?";
174         case DbType.VarNumeric: return "decimal?";
175         default:
176         {
177             return "__UNKNOWN__" + column.NativeType;
178         }
179     }
180 }
181 </script>
代碼

下載

GenrerateSqlDescription_8_28.zip 

相關文章
相關標籤/搜索