小程序大智慧,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里创建一个数据库项目,把表的创建脚本放在里面进行管理,就非常方便的。
由于习惯用自己的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=,CType=typeof(string),Description="业务编号")]
[DataMember(Order = )]
public virtual string BH{get;set;}
但是由于表创建脚本里的注释不能直接写入到数据库的表和字段中,所以注释的创建脚本我需要再写一次,我觉得比较不爽,于是我决定写个小工具从表的创建脚本里面抽取那些本来就写好的注释,从而减小重复机械的工作,也防止错误的发生。
这样一个程序非常简单,下面说一下思路
实现
一,写好带注释的表脚本,并提取这些信息
格式按文章开始讲到的那样写好,即"/*注释*/",“*”可以是多个,比如"/*********注释***********/",并将这些脚本存放到相同根目录
要提取这些注释,最大的功臣非正则表达式莫属了
a.提取表头的注释,也就是表名的解释正则表达式
private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");
b.提取列的注释正则表达式
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 生成映射类(已带注释)
核心代码
namespace GenrerateSqlDescription
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions; public class SqlNotesGenerator
{
private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");
private readonly Regex _columnsReg = new Regex(@"\[([\w]*)\][^\/]*/[\*]+([^\*]*)[\*]+/");
private const string TableDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user ',dbo,'table',[{1}];\r\n";
private const string ColumnDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user',dbo,'table',[{1}],'column','{2}';\r\n";
private const string TableDescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}];\r\n";
private const string ColumnescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}],'column','{1}';\r\n";
private const string CheckTableExistsSqlFormat = "IF OBJECT_ID(N'{0}',N'U') IS NOT NULL \r\nBEGIN \r\n";
private const string EndStr = "END";
private const string Tab = " "; public bool GenDrop { get; set; }
public string Path { get; set; } private string GetDescriptionSql(string path)
{
var sb = new StringBuilder();
var fs = File.OpenRead(path);
var fileRd = new StreamReader(fs);
var str = fileRd.ReadToEnd();
var tableMatch = _tableReg.Match(str);
if (tableMatch.Length < ) return string.Empty; var tableName = tableMatch.Groups[].Value;
var tableDes = tableMatch.Groups[].Value;
if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(tableDes)) return string.Empty; var columnStr = str.Substring(str.IndexOf("(", StringComparison.Ordinal));
var matches = _columnsReg.Matches(columnStr); sb.AppendFormat(CheckTableExistsSqlFormat, tableName); sb.Append(Tab);
if (GenDrop)
sb.AppendFormat(TableDescriptionDropSqlFormat, tableName);
else
sb.AppendFormat(TableDescriptionCrateSqlFormat, tableDes, tableName);
foreach (Match match in matches)
{
var columnName = match.Groups[].Value;
var description = match.Groups[].Value;
if (string.IsNullOrEmpty(columnName) || string.IsNullOrEmpty(description))
continue;
sb.Append(Tab);
if (GenDrop)
sb.AppendFormat(ColumnescriptionDropSqlFormat, tableName, columnName);
else
sb.AppendFormat(ColumnDescriptionCrateSqlFormat, description, tableName, columnName);
} sb.AppendLine(EndStr);
return sb.ToString();
} public string GetGenerateSql()
{
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);
} } }
SqlNotesGenerator
CodeSimith模版
<%--
Name:
Author:
Description:
--%>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="" Inherits="OutputFileCodeTemplate" Debug="False" Description="Template description here." %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Optional="True" Description="the table name" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Assembly Name="CodeSmith.BaseTemplates" %>
<%@ Import Namespace="CodeSmith.BaseTemplates" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Import Namespace="CodeSmith.CustomProperties" %>
//------------------------------------------------------------------------------
// <auto-generated>
// This code generated by the tool, do not propose to amend
// Generation time:<%=DateTime.Now%>
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Data;
using System.Runtime.Serialization;
using XDbFramework;
using BPM_M01.DataAccessLayer.Base;
using System.Xml.Serialization;
using System.Diagnostics;
using System.CodeDom.Compiler; namespace <%=Namespace%>
{
[Table(TableName = <%=this.SourceTable.Name%>.Table.Name ,Descripton = "<%=this.SourceTable.Description%>",GenreratePK = <%=GenreratePK.ToString().ToLower()%>)]
[GeneratedCodeAttribute("System.Xml", "2.0.50727.4927")]
[DebuggerStepThroughAttribute()]
public partial class <%=this.SourceTable.Name%> : DtoBase
{
public static class Table
{
public const string Name = "<%=this.SourceTable.Name%>";
}
public static class Columns
{
<%for(int i=; i<this.SourceTable.Columns.Count;i++)
{
string colName=this.SourceTable.Columns[i].Name;%>
public const string <%=colName%> = "<%=colName%>";
public const string <%=colName%>FullName =Table.Name + "." + "<%=colName%>";
<%}%>
} <%for(int i=; i<this.SourceTable.Columns.Count;i++)
{
int namelength=this.SourceTable.Columns[i].Name.Length;
string colName=this.SourceTable.Columns[i].Name;
if(colName == "ID" || colName == "IDNO") continue;
string titleCaseColumName = colName.Substring(,).ToUpper() + colName.Substring(,colName.Length-);
%> /// <summary>
/// <%=this.SourceTable.Columns[i].Description%>
/// </summary>
<%if(this.SourceTable.Columns[i].IsPrimaryKeyMember){%>
[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%>")]
<%}%>
<%else{%>
<%if(this.SourceTable.Columns[i].IsForeignKeyMember)%>
<%//
foreach(TableKeySchema tks in SourceTable.ForeignKeys)
{
// foreach(MemberColumnSchema mcs in tks.ForeignKeyMemberColumns)
{ //
if(mcs.Name == SourceTable.Columns[i].Name)
{
TableSchema ts= tks.PrimaryKeyTable;%>
[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%>")]
<% break;
}
}
}
%>
<%else{%>
[Column(ColumnName=Columns.<%=colName%>,FullName=Columns.<%=colName%>FullName,Index=<%=i%>,CType=typeof(<%=GetCSharpVariableType(this.SourceTable.Columns[i])%>),Description="<%=this.SourceTable.Columns[i].Description%>")]
<%}%>
<%}%>
[DataMember(Order = <%=i%>)]
public virtual <%=GetCSharpVariableType(this.SourceTable.Columns[i])%> <%=titleCaseColumName%>{get;set;} <%}%>
}
} <script runat="template">
// Override the OutputFile property and assign our specific settings to it.
[FileDialog(FileDialogType.Save, Title="Select Output File", Filter="C# Files (*.cs)|*.cs", DefaultExtension=".cs")]
public override string OutputFile
{
get {return base.OutputFile;}
set {base.OutputFile = value;}
}
private string _Namespace;
public string Namespace
{
get{return _Namespace;}
set{_Namespace = value;}
} public bool GenreratePK{get;set;}
</script>
<script runat="template">
public string GetSqlDBType(string type)
{
switch(type)
{
case "int": return "SqlDbType.Int,";
case "bit": return "SqlDbType.Bit,";
case "bigint": return "SqlDbType.BigInt,";
case "tinyint": return "SqlDbType.TinyInt,";
case "nvarchar": return "SqlDbType.NVarChar,";
case "date": return "SqlDbType.Date,";
case "datetime": return "SqlDbType.DateTime,";
case "char": return "SqlDbType.Char,";
case "decimal": return "SqlDbType.Decimal,";
case "float": return "SqlDbType.Float,";
case "image": return "SqlDbType.Image,";
case "money": return "SqlDbType.Money,";
case "nchar": return "SqlDbType.NChar,";
case "ntext": return "SqlDbType.NText,";
case "real": return "SqlDbType.Real,";
case "smalldatetime": return "SqlDbType.SmallDateTime,";
case "smallint": return "SqlDbType.SmallInt,";
case "smallmoney": return "SqlDbType.SmallMoney,";
case "text": return "SqlDbType.Text,";
case "timestamp": return "SqlDbType.Timestamp,";
case "udt": return "SqlDbType.Udt,";
case "uniqueidentifier": return "SqlDbType.UniqueIdentifier,";
case "varbinary": return "SqlDbType.VarBinary,";
case "varchar": return "SqlDbType.VarChar,";
case "variant": return "SqlDbType.Variant,";
case "xml": return "SqlDbType.Xml,";
default : return "";
} }
public string GetCSharpVariableType(ColumnSchema column)
{
switch (column.DataType)
{
case DbType.AnsiString: return "string";
case DbType.AnsiStringFixedLength: return "string";
case DbType.Binary: return "byte[]";
case DbType.Boolean: return "bool?";
case DbType.Byte: return "byte";
case DbType.Currency: return "decimal?";
case DbType.Date: return "DateTime?";
case DbType.DateTime: return "DateTime?";
case DbType.Decimal: return "decimal?";
case DbType.Double: return "double?";
case DbType.Guid: return "Guid";
case DbType.Int16: return "short?";
case DbType.Int32: return "int?";
case DbType.Int64: return "long?";
case DbType.Object: return "object";
case DbType.SByte: return "sbyte";
case DbType.Single: return "float?";
case DbType.String: return "string";
case DbType.StringFixedLength: return "string";
case DbType.Time: return "TimeSpan";
case DbType.UInt16: return "ushort?";
case DbType.UInt32: return "uint?";
case DbType.UInt64: return "ulong?";
case DbType.VarNumeric: return "decimal?";
default:
{
return "__UNKNOWN__" + column.NativeType;
}
}
}
</script>
代码
下载
GenrerateSqlDescription_8_28.zip
小程序大智慧,sqlserver 注释提取工具的更多相关文章
- sqlserver 注释提取工具
小程序大智慧,sqlserver 注释提取工具 开篇背景 我习惯在写表的创建脚本时将注释直接写在脚本里,比如 ? /*账套*/ CREATE TABLE [dbo].[AccountingBook] ...
- 小程序 web 端实时运行工具
微信小程序 web 端实时运行工具 https://chemzqm.github.io/wept/
- [RN] React Native代码转换成微信小程序代码的转换引擎工具
React Native代码转换成微信小程序代码的转换引擎工具 https://github.com/areslabs/alita
- webstorm开发微信小程序代码提醒(webstorm开发工具)
使用了微信提供的开发工具是真心难用,卡顿厉害.中英文切写注释换相当不爽.还没办法多开窗口,相信大家也遇到过这种现象. 下边我们介绍下webstorm来开发微信小程序的一些配置: File---sett ...
- 【微信小程序】在微信开发工具上七牛云的图片可以看到,但是在真机上看不到的原因解决
在开发微信小程序过程中,在微信开发者工具上,七牛云的图片都可以展示出来,但是在真机上,七牛云的图片却展示不出来,也没有报404找不到或者不能加载图片的问题, 必须保证: 1.图片是用image加载的: ...
- 微信小程序---账号注册与开发工具
(1)申请帐号 进入小程序注册页 根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号. 在这个小程序管理平台,你可以管理你的小程序的权限,查看数据报表,发布小程序等操作. 登录 小程序后台 ...
- 微信小程序 使用环信聊天工具
当时做微信小程序环信的时候,没有遇到太多的问题,因为找到了一个例子,有兴趣的朋友可以把这个包下载下来看一下,写的超级的号,使用起来也特别简单,appkey需要自己配置,从环信官网https://con ...
- php文档注释提取工具phpdocumentor的使用
phpDocumentor, 分为文档性注释, 和 非文档性注释; 命令为: phpdoc -h, -f, -d.... 提取/ 生成 程序的注释文档, 实际上有很多种工具, 如: doc++, do ...
- 微信小程序(10)--开发者工具更新以后wxss编译错误
更新最新版微信开发者工具后,出现下面报错: 解决办法: 1.在控制台输入openVendor() ,确定Enter: 2.清除里面的wcc.exe wcsc.exe : 3.重启开发者工具
随机推荐
- C#并行编程
C#并行编程中的Parallel.Invoke 一.基础知识 并行编程:并行编程是指软件开发的代码,它能在同一时间执行多个计算任务,提高执行效率和性能一种编程方式,属于多线程编程范畴.所以我们在设计过 ...
- T-SQL中default值的使用
今天介绍一下通过T-SQL语句来创建表时使用default的关键字来自动使用默认值,这个关键字和其它的如:identity,primary key ,not null ,unique等不是相同,这里简 ...
- 白板编程浅谈——Why, What, How(转)
原文链接:http://lucida.me/blog/whiteboard-coding-demystified/ 这篇文章节选自我正在撰写的一本关于应届生面试求职的书籍,欢迎在评论或微博(@peng ...
- 举例说, Decorator模式(Decorator Pattern)
前言 在食品工业中的装饰图案具有比较广泛的应用,大多数的两个图案和在网上的例子饮食相关的,一旦被称为电影的手表,点咖啡要加糖要加奶昔要加这加那的时候.感觉好有派~好高大上啊~.为啥我在小卖部都是 ...
- 得到JAVA项目根文件夹
获得的相对路径 说明:相对路径(这并不说明什么时候相对谁)可以通过以下来获得(无论是一般java项目或web工程) String path = System.getProperty("use ...
- H. 硬币的水问题II
H. 硬币水题II Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: ...
- 合理设置MTU,提升下载速度
可能很少有雷友注意过“本机.网络”的“MTU”值对自己网络性能产生的影响.对于追求更快的下载速度来说,MTU值设置不当,就仿佛穿着高跟鞋跑步一般. MTU是什么? “MTU=最大传输单元 单位:字节” ...
- C# 中使用WebClient 请求 https
WebClient 请求 启用SSL的站点 时,如果站点的证书是不可信的,请求会被阻止,解决办法如下: 添加以下代码: ServicePointManager.ServerCertificateVal ...
- CSDN上看到的一篇有关Spring JDBC事务管理的文章(内容比较全) (转)
JDBC事务管理 Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction ma ...
- 在SQL Server Management Studio中可以运行作业但是用T-SQL运行则失败
原文:在SQL Server Management Studio中可以运行作业但是用T-SQL运行则失败 问题: 在SQL Server Management Studio中可以运行作业但是用T-SQ ...