2022-10-23 332
我们现有的项目没有采用任何ORM,所有的数据读取与操作都是基于存储过程的,在代码端使用 Enterprise Library 5 。 在 EntLib 和数据库之间,是基于我原来写的一个 T4 实体生成的模板,之前也没有详细的去整,反正能运行出结果就行了,总之,代码很乱。
最近一期项目告一段落,后续项目还没有上马,一手把这个部门建立起来的总监(经理)又离开了这个团队,我们几个老一批的员工也在思索着是否换换。趁着这个便当,我把这个东西在整出来,算是给我增加一个砝码吧。
什么是 T4 模板,自己去搜吧,怎么用也请自己搜吧。懂就懂,不懂我也懒得解释。
我将要贴出的T4模板是将 SQLServer 2008 的 Table, View , TableType, Procedure 解析为 C# 里的对应实体,形如下:
Table/View/TableType
usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Data; usingSystem.Collections; usingSystem.ComponentModel; usingSystem.Runtime.Serialization; namespaceAsNum.MySecret.Entity.Database{ ///<summary> ///Table:dbo.LoginPolicy ///登陆策略 ///数据实体 ///</summary> [Serializable] [DataContract] publicclassLoginPolicyEntity{ ///<summary> ///自动编号 ///dbo.LoginPolicy.PolicyID ///默认值 ///</summary> publicintPolicyID{ get;set; } privateint_UnfreezeTime=30; ///<summary> ///解冻时间 ///dbo.LoginPolicy.UnfreezeTime ///默认值((30)) ///</summary> publicintUnfreezeTime{ get{ return_UnfreezeTime; } set{ _UnfreezeTime=value; } } privateint_MaxFailedCount=5; ///<summary> ///最大失败次数 ///dbo.LoginPolicy.MaxFailedCount ///默认值((5)) ///</summary> publicintMaxFailedCount{ get{ return_MaxFailedCount; } set{ _MaxFailedCount=value; } } privatebool?_EnableLoginPolicy=true; ///<summary> ///是否启用登陆策略 ///dbo.LoginPolicy.EnableLoginPolicy ///默认值((1)) ///</summary> publicbool?EnableLoginPolicy{ get{ return_EnableLoginPolicy; } set{ _EnableLoginPolicy=value; } } privateDateTime_CreateTime=newDateTime(); ///<summary> /// ///dbo.LoginPolicy.CreateTime ///默认值(getdate()) ///</summary> publicDateTimeCreateTime{ get{ return_CreateTime; } set{ _CreateTime=value; } } ///<summary> /// ///dbo.LoginPolicy.Creator ///默认值 ///</summary> publicstringCreator{ get;set; } } }
Procedure
usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Data; usingSystem.Collections; usingSystem.ComponentModel; usingSystem.Data.SqlClient; usingMicrosoft.Practices.EnterpriseLibrary.Data; usingAsNum.MySecret.Entity.Database; usingAsNum.Common.Extend; namespaceAsNum.MySecret.DB{ /// /// /// publicpartialclassSPs{ /// ///发送消息 /// /// ///@Title消息标题 ///@Ctx消息内容 ///@UserID用户ID ///@FromIP发消息的IP ///@IntranetIP发消息的内网IP,用于扩展 ///@IsPublic是否公开 ///@Receiver消息接收者,表变量 /// publicstaticSqlCommandSendMsg(Databasedb,stringtitle,stringctx,int?userID,long?fromIP,long?intranetIP,long?isPublic,Listreceiver){ if(db==null) thrownewArgumentNullException("db"); SqlCommandsc=newSqlCommand("SendMsg"); sc.CommandType=CommandType.StoredProcedure; db.AddParameter(sc,"@Title",DbType.String,100,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,title); db.AddParameter(sc,"@Ctx",DbType.String,500,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,ctx); db.AddParameter(sc,"@UserID",DbType.Int32,4,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,userID); db.AddParameter(sc,"@FromIP",DbType.Int64,8,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,fromIP); db.AddParameter(sc,"@IntranetIP",DbType.Int64,8,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,intranetIP); db.AddParameter(sc,"@IsPublic",DbType.Int64,8,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,isPublic); db.AddParameter(sc,"@Receiver",DbType.Object,-1,ParameterDirection.Input,true,0,0,String.Empty,DataRowVersion.Default,receiver.ToDataTable()); returnsc; } } }
可以看到产生的存储过程调用方法并没有获取到参数的默认值,这个是因为(http://msdn.microsoft.com/en-us/library/ms176074.aspx):
SQL Server only maintains default values for CLR objects in this catalog view;
不过,有牛人做出来了,前提是存储过程没有加密:
http://www.codeproject.com/KB/database/FindDefaultValueSPParams.aspx
#p#
在声明 Table / View / TableType 的时候:
CREATETYPETMessageReceiverASTABLE( SendTypeVARCHAR(10)NOTNULL, ReceiverNVARCHAR(128)NOTNULL ) GO EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'消息接收人,相同SendType和Recever只能出现一次',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TYPE',@level1name=N'TMessageReceiver' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'消息发送类型EML(QQ,MSN留扩展)',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TYPE',@level1name=N'TMessageReceiver',@level2type=N'COLUMN',@level2name=N'SendType' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'接收地址,跟据SendType',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TYPE',@level1name=N'TMessageReceiver',@level2type=N'COLUMN',@level2name=N'Receiver' GO
————
CREATETABLELoginPolicy( PolicyIDINTIDENTITY(1,1)NOTNULL, UnfreezeTimeINTNOTNULLDEFAULT30, MaxFailedCountINTNOTNULLDEFAULT5, EnableLoginPolicyBITDEFAULT1,--0:不启用,1:启用 CreateTimeDATETIMENOTNULLDEFAULTGETDATE(), CreatorNVARCHAR(30), CONSTRAINTLoginPolicy_PKPRIMARYKEY(PolicyID) ) GO EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'登陆策略',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'LoginPolicy' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'自动编号',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'LoginPolicy',@level2type=N'COLUMN',@level2name=N'PolicyID' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'解冻时间',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'LoginPolicy',@level2type=N'COLUMN',@level2name=N'UnfreezeTime' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'最大失败次数',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'LoginPolicy',@level2type=N'COLUMN',@level2name=N'MaxFailedCount' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'是否启用登陆策略',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'LoginPolicy',@level2type=N'COLUMN',@level2name=N'EnableLoginPolicy' GO
声明存储过程:
CREATEPROCEDURESendMsg @TitleNVARCHAR(100), @CtxNVARCHAR(500), @UserIDINT, @FromIPBIGINT, @IntranetIPBIGINT, @IsPublicBIGINT, @ReceiverTMessageReceiverREADONLY AS BEGIN --表变量,用以存储新增的主表ID DECLARE@TASTABLE(IDINT) BEGINTRANNewMsg BEGINTRY --写入主表 INSERTINTO[Message] (Title,Ctx,UserID,FromIP,IntranetIP,IsPublic) OUTPUTINSERTED.MessageIDINTO@T VALUES (@Title,@Ctx,@UserID,@FromIP,@IntranetIP,@IsPublic) --取出新增数据的ID DECLARE@MessageIDINT SELECTTOP1@MessageID=IDFROM@T --写子表,这里要改动一下,相同的只保留一条 INSERTINTOMessageReceiver (MessageID,SendType,Receiver) SELECT @MessageID,R.SendType,R.Receiver FROM @ReceiverR ENDTRY BEGINCATCH ROLLBACKTRANNewMsg RETURN2--DatabaseError ENDCATCH COMMITTRANNewMsg RETURN0 END GO EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'发送消息',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'消息标题',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@Title' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'消息内容',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@Ctx' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'用户ID',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@UserID' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'发消息的IP',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@FromIP' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'发消息的内网IP,用于扩展',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@IntranetIP' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'是否公开',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@IsPublic' EXECsys.sp_addextendedproperty@name=N'MS_Description',@value=N'消息接收者,表变量',@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'PROCEDURE',@level1name=N'SendMsg',@level2type=N'PARAMETER',@level2name='@Receiver' GO
这些 MS_Description 的 value 会做为注释写到生成的代码里。
实现T4模板就很简单了,就是把下面几个SQL的结果取出来,在自由的组合一下:
WITHEntitiesAS( SELECT Table_catalogAS[Database] ,table_schema[Owner] ,table_name[Name] ,'Table'[Type] ,OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME)ID FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASETABLE' UNIONALL SELECT Table_catalog ,table_schema ,table_name ,'View' ,OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME)ID FROM information_schema.views UNIONALL SELECT DB_NAME() ,SCHEMA_NAME(schema_id) ,name ,'TableType' ,user_type_id FROM sys.table_types ) SELECT E.* ,P.valueAS[DESC] FROM EntitiesE LEFTJOINsys.extended_propertiesPONE.ID=P.major_idANDP.minor_id=0
Table / View / TableType
字段:
SELECT DB_NAME()AS[Database] ,COALESCE(SCHEMA_NAME(T.Schema_id),OBJECT_SCHEMA_NAME(C.object_id))ASOwner ,COALESCE(T.Name,OBJECT_NAME(c.OBJECT_ID))ASParent ,C.column_idASOrdinalPosition ,C.nameASName ,TYPE_NAME(c.user_type_id)ASDataType ,D.definitionASDefaultSetting ,C.is_nullableASIsNullable ,C.max_lengthASMaxLength ,COLUMNPROPERTY(C.OBJECT_ID,C.Name,'PRECISION')AS[Precision]--用于判断NVARCHAR实际长度的 --,C.Object_id,P.major_id,P.minor_id ,P.ValueAS[DESC] FROM sys.columnsC LEFTJOINsys.table_typesTONT.type_table_object_id=C.object_ID LEFTJOINsys.default_constraintsDONC.object_id=D.parent_object_idANDD.parent_column_id=C.Column_id LEFTJOINsys.extended_propertiesPON(P.major_id=C.OBJECT_IDORP.major_id=T.User_type_id)ANDP.minor_id=C.COLUMN_IDANDP.name='MS_Description' WHERE COALESCE(SCHEMA_NAME(T.Schema_id),OBJECT_SCHEMA_NAME(C.object_id))='dbo'
存储过程:
SELECT SCHEMA_NAME(P.schema_id)ASOwner ,P.Name ,PP.ValueAS[Desc] FROM sys.proceduresP LEFTJOINsys.extended_propertiesPPONP.object_id=PP.major_idANDPP.minor_id=0
存储过程的参数:
SELECT SCHEMA_NAME(P.[schema_id])AS[Schema] ,P.NameAS[Proc] ,PA.Name ,(SELECTCOUNT(1)FROMsys.table_typesWHEREuser_type_id=PA.user_type_id)ASIsTableType ,TYPE_NAME(PA.user_type_id)ASDataType ,PA.max_lengthASMaxLength ,COLUMNPROPERTY(PA.OBJECT_ID,PA.Name,'PRECISION')AS[Precision]--用于判断NVARCHAR实际长度的 ,PA.is_outputASIsOutput ,PP.valueAS[Desc] FROM sys.proceduresP INNERJOINsys.parametersPAONP.object_id=PA.object_id LEFTJOINsys.extended_propertiesPPONPA.object_id=PP.major_idANDPA.parameter_id=PP.minor_id ORDERBY PA.Object_id,PA.Parameter_id
源代码包:http://files.cnblogs.com/xling/ExecuteT4.7z
这个包里有一个如何用程序运行T4模板的示例,加这个是因为同事问我如何用代码去执行T4模板,昨晚K歌完到家12点半(跟经理道别),洗完澡后,我从以前写的代码里翻出来的,稍稍做了点修改。还有一份数据字典导出模板.
另外需要注意的是:
1, Microsoft.VisualStudio.TextTemplating.dll 这个 DLL,如果你装的是VS2010 就默认装了这个。如果是VS2008, 需要从:Visual Studio 2008 SDK 1.1 里找
2, 如图
遗留的问题:
有些默认值没有处理好,比如对DateTime字段只处理了这种情况: GETDATE() 或 ‘2011-01-01’ , 其它的我暂时没有遇到,没有做处理。
存储过程的 TableType 参数,我简单的映射为 DbType.Object ,还没有验证这样是否可行。
后面我会把这些都修正的,如果你有兴趣的话,可以留意。
原文链接:https://77isp.com/post/6896.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2023-01-07
网站技术 2022-11-26
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
小游客游戏攻略网游戏攻略网 2024年07月26日
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
扫码二维码
获取最新动态