如何用T4模板生成数据实体 我们现有的项目没有采用任何ORM,所有的数据读取与操作都是基于存储过程的,在代码端使用 Enterprise Library 5 。 在 EntLib 和数据库之间,是基于我原来写的一个 T4 实体生成的模板,之前也没有详细的去整,反正能运行出结果就行了,总之,代码很乱。 最近一期项目告一段落,后续项目还没有上马,一手把这个部门建立起来的总监(经理)又离开了这个团队,我们几个老一批的员工也在思索着是否换换。趁着这个便当,我把这个东西在整出来,算是给我增加一个砝码吧。 什么是 T4 模板,自己去搜吧,怎么用也请自己搜吧。懂就懂,不懂我也懒得解释。 我将要贴出的T4模板是将 SQLServer 2008 的 Table, View , TableType, Procedure 解析为 C# 里的对应实体,形如下: Table/View/TableType using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Collections; using System.ComponentModel; using System.Runtime.Serialization; namespace AsNum.MySecret.Entity.Database { /// 《summary》 /// Table : dbo.LoginPolicy /// 登陆策略 /// 数据实体 /// 《/summary》 [Serializable] [DataContract] public class LoginPolicyEntity { /// 《summary》 /// 自动编号 /// dbo.LoginPolicy.PolicyID /// 默认值 /// 《/summary》 public int PolicyID{ get;set; } private int _UnfreezeTime = 30; /// 《summary》 /// 解冻时间 /// dbo.LoginPolicy.UnfreezeTime /// 默认值((30)) /// 《/summary》 public int UnfreezeTime{ get{ return _UnfreezeTime; } set{ _UnfreezeTime = value; } } private int _MaxFailedCount = 5; /// 《summary》 /// 最大失败次数 /// dbo.LoginPolicy.MaxFailedCount /// 默认值((5)) /// 《/summary》 public int MaxFailedCount{ get{ return _MaxFailedCount; } set{ _MaxFailedCount = value; } } private bool? _EnableLoginPolicy = true; /// 《summary》 /// 是否启用登陆策略 /// dbo.LoginPolicy.EnableLoginPolicy /// 默认值((1)) /// 《/summary》 public bool? EnableLoginPolicy{ get{ return _EnableLoginPolicy; } set{ _EnableLoginPolicy = value; } } private DateTime _CreateTime = new DateTime(); /// 《summary》 /// /// dbo.LoginPolicy.CreateTime /// 默认值(getdate()) /// 《/summary》 public DateTime CreateTime{ get{ return _CreateTime; } set{ _CreateTime = value; } } /// 《summary》 /// /// dbo.LoginPolicy.Creator /// 默认值 /// 《/summary》 public string Creator{ get;set; } } } Procedure using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Collections; using System.ComponentModel; using System.Data.SqlClient; using Microsoft.Practices.EnterpriseLibrary.Data; using AsNum.MySecret.Entity.Database; using AsNum.Common.Extend; namespace AsNum.MySecret.DB { public partial class SPs { /// /// 发送消息 /// /// /// @Title 消息标题 /// @Ctx 消息内容 /// @UserID 用户ID /// @FromIP 发消息的IP /// @IntranetIP 发消息的内网IP,用于扩展 /// @IsPublic 是否公开 /// @Receiver 消息接收者,表变量 /// public static SqlCommand SendMsg(Database db, string title , string ctx , int? userID , long? fromIP , long? intranetIP , long? isPublic , List receiver){ if(db == null) throw new ArgumentNullException(“db”); SqlCommand sc = new SqlCommand(“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()); return sc; } } } 可以看到产生的存储过程调用方法并没有获取到参数的默认值,这个是因为(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 在声明 Table / View / TableType 的时候: CREATE TYPE TMessageReceiver AS TABLE( SendType VARCHAR(10) NOT NULL, Receiver NVARCHAR(128) NOT NULL ) GO EXEC sys.sp_addextendedproperty @name=N‘MS_Description’, @value=N‘消息接收人, 相同SendType 和Recever 只能出现一次’ , @level0type=N‘SCHEMA’,@level0name=N‘dbo’, @level1type=N‘TYPE’,@level1name=N‘TMessageReceiver’ EXEC sys.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’ EXEC sys.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 ------------ CREATE TABLE LoginPolicy( PolicyID INT IDENTITY(1,1) NOT NULL, UnfreezeTime INT NOT NULL DEFAULT 30, MaxFailedCount INT NOT NULL DEFAULT 5, EnableLoginPolicy BIT DEFAULT 1, -- 0 : 不启用, 1:启用 CreateTime DATETIME NOT NULL DEFAULT GETDATE(), Creator NVARCHAR(30), CONSTRAINT LoginPolicy_PK PRIMARY KEY (PolicyID) ) GO EXEC sys.sp_addextendedproperty @name=N‘MS_Description’, @value=N‘登陆策略’ , @level0type=N‘SCHEMA’,@level0name=N‘dbo’, @level1type=N‘TABLE’,@level1name=N‘LoginPolicy’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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 声明存储过程: CREATE PROCEDURE SendMsg @Title NVARCHAR(100), @Ctx NVARCHAR(500), @UserID INT, @FromIP BIGINT, @IntranetIP BIGINT, @IsPublic BIGINT, @Receiver TMessageReceiver READONLY AS BEGIN -- 表变量,用以存储新增的主表ID DECLARE @T AS TABLE (ID INT) BEGIN TRAN NewMsg BEGIN TRY -- 写入主表 INSERT INTO [Message] (Title, Ctx, UserID, FromIP, IntranetIP, IsPublic) OUTPUT INSERTED.MessageID INTO @T VALUES (@Title, @Ctx, @UserID, @FromIP, @IntranetIP , @IsPublic ) -- 取出新增数据的ID DECLARE @MessageID INT SELECT TOP 1 @MessageID = ID FROM @T -- 写子表, 这里要改动一下,相同的只保留一条 INSERT INTO MessageReceiver (MessageID, SendType, Receiver ) SELECT @MessageID, R.SendType, R.Receiver FROM @Receiver R END TRY BEGIN CATCH ROLLBACK TRAN NewMsg RETURN 2 -- DatabaseError END CATCH COMMIT TRAN NewMsg RETURN 0 END GO EXEC sys.sp_addextendedproperty @name=N‘MS_Description’, @value=N‘发送消息’ , @level0type=N‘SCHEMA’,@level0name=N‘dbo’, @level1type=N‘PROCEDURE’,@level1name=N‘SendMsg’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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’ EXEC sys.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 会做为注释写到生成的代码里。
开源时代的到来,对与技术人员是一个巨大的考验
QQ:876162454
|