使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件。 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码。 模型是包含有关应用程序要求的关键信息的文件或数据库。像一些常用的框架,基本都是根据数据库模型来生成代码框架的。

一、具体步骤

1、选择“文本模板

  新建项目名为:T4Sample,添加新项,选择“文本模板”即可创建设计时模板

模板属性,请确认:

  • 自定义工具 = TextTemplatingFileGenerator
  • 生成操作 = 无

打开模板,默认下面几行语句

  1. <#@ template debug="false" hostspecific="false" language="C#" #>
  2. <#@ assembly name="System.Core" #>
  3. <#@ import namespace="System.Linq" #>
  4. <#@ import namespace="System.Text" #>
  5. <#@ import namespace="System.Collections.Generic" #>
  6. <#@ output extension=".txt" #>

2、修改模板

  依然以HelloWorld为例

  1. <#@ template debug="false" hostspecific="false" language="C#" #>
  2. <#@ assembly name="System.Core" #>
  3. <#@ import namespace="System.Linq" #>
  4. <#@ import namespace="System.Text" #>
  5. <#@ import namespace="System.Collections.Generic" #>
  6. <#@ output extension=".cs" #>
  7.  
  8. using System;
  9.  
  10. namespace Test
  11. {
  12. public class HelloWorld
  13. {
  14. public static void Main(string[] args)
  15. {
  16. <#
  17. List<Person> people = GetPersonList();
  18. foreach(Person p in people)
  19. {
  20. #>
  21. Console.WriteLine("Hello {0},Welcome to T4 World!","<#= p.Name #>");
  22. <#}
  23. #>
  24. }
  25. }
  26. }
  27.  
  28. <#+
  29. //类
  30. public class Person
  31. {
  32. ///名称
  33. public string Name{ get; set; }
  34.  
  35. public Person(string name)
  36. {
  37. this.Name = name;
  38. }
  39. }
  40. //初始化众人
  41. public List<Person> GetPersonList()
  42. {
  43. List<Person> people = new List<Person>();
  44.  
  45. Person p1 = new Person("Tom");
  46. Person p2 = new Person("Jim");
  47. Person p3 = new Person("Lucy");
  48.  
  49. people.Add(p1);
  50. people.Add(p2);
  51. people.Add(p3);
  52.  
  53. return people;
  54. }
  55.  
  56. #>

3、生成代码

  可通过以下方式

  • 保存,自动转换模板。
  • 或者右击模板文件,选择“运行自定义工具”
  • 或者在“解决方案资源管理器”工具栏中单击“转换所有模板”。 这将转换 Visual Studio 解决方案中的所有模板。

生成代码如下:

  1. using System;
  2.  
  3. namespace Test
  4. {
  5. public class HelloWorld
  6. {
  7. public static void Main(string[] args)
  8. {
  9. Console.WriteLine("Hello {0},Welcome to T4 World!", "Tom");
  10. Console.WriteLine("Hello {0},Welcome to T4 World!", "Jim");
  11. Console.WriteLine("Hello {0},Welcome to T4 World!", "Lucy");
  12. }
  13. }
  14. }

二、模板指令

  C#代码与T4不同,就是引用、调试、输出等方面,而T4中最重要的指令Template ,就包含这些不同。所以这里特别重点强调下指令Template

使用 Template 指令

  1. <#@ template [language="C#"] [hostspecific="true"] [debug="true"] [inherits="templateBaseClass"] [culture="code"][compilerOptions="options"] #>

template 指令有多个特性,通过这些特性可以指定转换的不同方面。 所有特性都是可选的。

1、compilerOptions 特性

示例:
    compilerOptions="optimize+"
有效值:
    任何有效的编译器选项。
在模板已经转换为 Visual C# 或 Visual Basic 并且生成的代码已编译时会应用这些选项。

2、culture 特性

示例:
    culture="de-CH"
有效值:
    "",不变的区域性,它是默认值。
    表示为 xx-XX 形式字符串的区域性。 例如:en-US、ja-JP、de-CH、de-DE。
Culture 特性指定将表达式块转换为文本时要使用的区域性。

3、debug 特性

示例:
    debug="true"
有效值:
    true, false. 默认值为 false。
debug 特性指定是否启用调试。 如果是 true,则中间代码文件将包含使调试器能够识别模板中中断或异常发生位置的信息。 对于设计时模板,中间代码文件将写入您的 %TEMP% 目录。
若要在模板执行的特定点启动调试器,请插入对 Launch 的调用。 若要在后续的点处中断执行,请插入对 Break 的调用。

  1. <#@ template debug="true" language="C#" #>
  2. <#@ output extension=".txt" #>
  3. Output something.
  4. <#
  5. // Break here:
  6. System.Diagnostics.Debugger.Launch();
  7. #>
  8. Output more.
  9. <#
  10. // Break here also:
  11. System.Diagnostics.Debugger.Break();
  12. #>
  13. Output more.

4、hostspecific 特性

有效值:
    true, false. 默认值为 false。
如果将此特性的值设置为 true,则会将名为 Host 的属性添加到由文本模板生成的类中。 该属性是对转换引擎的宿主的引用,并声明为 Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost。 如果已经定义了自定义宿主,则可以将其转换为自定义宿主类型。因为此属性的类型取决于宿主的类型,所以仅当编写只适用于特定宿主的文本模板时才有用。
当 hostspecific 为 true,而且正在使用 Visual Studio 时,可以将 this.Host 强制转换为 IServiceProvider,以访问 Visual Studio 功能。 还可以使用 Host.ResolvePath(filename) 来获得项目中文件的绝对路径。

5、language 特性

示例:
    language="VB"
有效值:
    C#(默认值)
    VB(值 VBv3.5 和 C#v3.5 在此版本中已过时,但是会解释为 VB 和 C#。)
language 特性指定要用于语句和表达式块中的源代码的语言(Visual Basic 或 Visual C#)。 从中生成输出的中间代码文件将使用此语言。 此语言与您的模板生成的语言无关,它可以是任何类型的文本。

6、inherits 特性

可以指定模板的程序代码可以继承自另一个类,这个类也可以从文本模板生成。

三、实例:代码生成器

该实例,就是我们通常见过的,模型代码生成器,根据数据模型生成代码框架,如模型层、数据访问层等。本实例先根据数据表,生存模型层代码。这是一个简单实例,如果有功夫,您可以根据这个原理写出自己的代码生成框架。

  1. <#@ template debug="false" hostspecific="false" language="C#" #>
  2. <#@ output extension=".cs" #>
  3. <#@ assembly name="System.Data" #>
  4. <#@ assembly name="System.Xml" #>
  5. <#@ import namespace="System" #>
  6. <#@ import namespace="System.Xml" #>
  7. <#@ import namespace="System.Data" #>
  8. <#@ import namespace="System.Data.SqlClient" #>
  9. <#
  10. ModelManager manager = new ModelManager();
  11. string tableName = "Dictionary";
  12. DataTable table= manager.GetTableSchema(tableName);
  13. #>
  14. using System;
  15.  
  16. namespace Model
  17. {
  18. public class <#= tableName #>
  19. {
  20. <#
  21. foreach(DataRow row in table.Rows)
  22. {
  23. #>
  24. public <#= manager.TransFromSqlType(row["DataType"].ToString())#> <#=row["ColumnName"]#>{ get; set; }
  25.  
  26. <#}
  27. #>
  28. }
  29. }
  30.  
  31. <#+
  32. public class ModelManager
  33. {
  34. /// <summary>
  35. /// 获得数据连接
  36. /// </summary>
  37. /// <returns></returns>
  38. private SqlConnection GetConnection()
  39. {
  40. return new SqlConnection("server=10.126.124.0;database=ZSOtherData;uid=it_zs;pwd=dev4ZS@2018;");
  41. }
  42.  
  43. /// <summary>
  44. ///
  45. /// </summary>
  46. /// <param name="tableName"></param>
  47. public DataTable GetTableSchema(string tableName)
  48. {
  49. DataTable dt;
  50. using (SqlConnection con = GetConnection())
  51. {
  52. con.Open();
  53.  
  54. SqlCommand cmd = con.CreateCommand();
  55. cmd.CommandText = string.Format(@"SELECT TABLE_NAME AS TableName ,
  56. ORDINAL_POSITION AS ColumnID ,
  57. COLUMN_NAME AS ColumnName ,
  58. DATA_TYPE AS DataType ,
  59. CASE WHEN IS_NULLABLE = 'NO' THEN 'false'
  60. ELSE 'true'
  61. END AS IsNullable
  62. FROM INFORMATION_SCHEMA.COLUMNS AS A
  63. LEFT JOIN sysobjects AS B ON A.TABLE_NAME = B.name
  64. WHERE A.TABLE_NAME = '{0}'",tableName);
  65. cmd.CommandType = CommandType.Text;
  66.  
  67. SqlDataAdapter adapter = new SqlDataAdapter(cmd);
  68. DataSet ds = new DataSet();
  69. adapter.Fill(ds);
  70. dt = ds.Tables[];
  71. }
  72.  
  73. return dt;
  74. }
  75. /// <summary>
  76. /// SQL
  77. /// </summary>
  78. /// <param name="type"></param>
  79. /// <returns></returns>
  80. public string TransFromSqlType(string type)
  81. {
  82. if (string.IsNullOrEmpty(type))
  83. {
  84. return string.Empty;
  85. }
  86.  
  87. if (string.Equals(type, "int", StringComparison.OrdinalIgnoreCase))
  88. {
  89. return "int";
  90. }
  91. else if (string.Equals(type, "varchar", StringComparison.OrdinalIgnoreCase))
  92. {
  93. return "string";
  94. }
  95.  
  96. return "string";
  97. }
  98.  
  99. }
  100. #>

四、调试T4模板

你可以在T4文本模板中设置断点。

  • 要调试的设计时文本模板,将文本模板文件,保存,然后选择解决方案资源管理器中的文件的快捷菜单上的“调试 T4 模板”。
  • 若要调试的运行时文本模板,只需调试它属于该应用程序。

1、

五、一次生成多个文件

https://blog.csdn.net/shuai7boy/article/details/53203294

一次生成一个文件:

Customers.tt

  1. <#@ include file="$(ProjectDir)DbHelper.ttinclude" #>
  2. using System;
  3. namespace T4ConsoleApplication.Entities
  4. {
  5. public class <#=config.TableName#>
  6. {
  7. <# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName)){#>
  8.  
  9. public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName#> { get; set; }
  10. <#}#>
  11. }
  12. }
  13.  
  14. <#+
  15. public class config
  16. {
  17. //修改要生成的数据库表
  18. public static readonly string ConnectionString="server=10.126.124.60;database=ZSOtherData;uid=it_zs;pwd=dev4ZS@2018;";
  19. public static readonly string DbDatabase="ZSOtherData";
  20. public static readonly string TableName="Mould";
  21. }
  22. #>

DbHelper.ttinclude

  1. <#@ assembly name="System.Core.dll" #>
  2. <#@ assembly name="System.Data.dll" #>
  3. <#@ assembly name="System.Data.DataSetExtensions.dll" #>
  4. <#@ assembly name="System.Xml.dll" #>
  5. <#@ import namespace="System" #>
  6. <#@ import namespace="System.Data" #>
  7. <#@ import namespace="System.Xml" #>
  8. <#@ import namespace="System.Linq" #>
  9. <#@ import namespace="System.Data" #>
  10. <#@ import namespace="System.Data.SqlClient" #>
  11. <#@ import namespace="System.Collections.Generic" #>
  12. <#+
  13. public class DbHelper
  14. {
  15. #region GetDbTables
  16.  
  17. public static List<DbTable> GetDbTables(string connectionString, string database, string tables = null)
  18. {
  19.  
  20. if (!string.IsNullOrEmpty(tables))
  21. {
  22. tables = string.Format(" and obj.name in ('{0}')", tables.Replace(",", "','"));
  23. }
  24. #region SQL
  25. string sql = string.Format(@"SELECT
  26. obj.name tablename,
  27. schem.name schemname,
  28. idx.rows,
  29. CAST
  30. (
  31. CASE
  32. WHEN (SELECT COUNT(1) FROM sys.indexes WHERE object_id= obj.OBJECT_ID AND is_primary_key=1) >=1 THEN 1
  33. ELSE 0
  34. END
  35. AS BIT) HasPrimaryKey
  36. from {0}.sys.objects obj
  37. inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
  38. INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
  39. where type='U' {1}
  40. order by obj.name", database, tables);
  41. #endregion
  42. DataTable dt = GetDataTable(connectionString, sql);
  43. return dt.Rows.Cast<DataRow>().Select(row => new DbTable
  44. {
  45. TableName = row.Field<string>("tablename"),
  46. SchemaName = row.Field<string>("schemname"),
  47. Rows = row.Field<int>("rows"),
  48. HasPrimaryKey = row.Field<bool>("HasPrimaryKey")
  49. }).ToList();
  50. }
  51. #endregion
  52.  
  53. #region GetDbColumns
  54.  
  55. public static List<DbColumn> GetDbColumns(string connectionString, string database, string tableName, string schema = "dbo")
  56. {
  57. #region SQL
  58. string sql = string.Format(@"
  59. WITH indexCTE AS
  60. (
  61. SELECT
  62. ic.column_id,
  63. ic.index_column_id,
  64. ic.object_id
  65. FROM {0}.sys.indexes idx
  66. INNER JOIN {0}.sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id
  67. WHERE idx.object_id =OBJECT_ID(@tableName) AND idx.is_primary_key=1
  68. )
  69. select
  70. colm.column_id ColumnID,
  71. CAST(CASE WHEN indexCTE.column_id IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey,
  72. colm.name ColumnName,
  73. systype.name ColumnType,
  74. colm.is_identity IsIdentity,
  75. colm.is_nullable IsNullable,
  76. cast(colm.max_length as int) ByteLength,
  77. (
  78. case
  79. when systype.name='nvarchar' and colm.max_length>0 then colm.max_length/2
  80. when systype.name='nchar' and colm.max_length>0 then colm.max_length/2
  81. when systype.name='ntext' and colm.max_length>0 then colm.max_length/2
  82. else colm.max_length
  83. end
  84. ) CharLength,
  85. cast(colm.precision as int) Precision,
  86. cast(colm.scale as int) Scale,
  87. prop.value Remark
  88. from {0}.sys.columns colm
  89. inner join {0}.sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id
  90. left join {0}.sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id
  91. LEFT JOIN indexCTE ON colm.column_id=indexCTE.column_id AND colm.object_id=indexCTE.object_id
  92. where colm.object_id=OBJECT_ID(@tableName)
  93. order by colm.column_id", database);
  94. #endregion
  95. SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, ) { Value = string.Format("{0}.{1}.{2}", database, schema, tableName) };
  96. DataTable dt = GetDataTable(connectionString, sql, param);
  97.  
  98. return dt.Rows.Cast<DataRow>().Select(row => new DbColumn()
  99. {
  100. ColumnID = row.Field<int>("ColumnID"),
  101. IsPrimaryKey = row.Field<bool>("IsPrimaryKey"),
  102. ColumnName = row.Field<string>("ColumnName"),
  103. ColumnType = row.Field<string>("ColumnType"),
  104. IsIdentity = row.Field<bool>("IsIdentity"),
  105. IsNullable = row.Field<bool>("IsNullable"),
  106. ByteLength = row.Field<int>("ByteLength"),
  107. CharLength = row.Field<int>("CharLength"),
  108. Scale = row.Field<int>("Scale"),
  109. Remark = row["Remark"].ToString()
  110. }).ToList();
  111. }
  112.  
  113. #endregion
  114.  
  115. #region GetDataTable
  116.  
  117. public static DataTable GetDataTable(string connectionString, string commandText, params SqlParameter[] parms)
  118. {
  119. using (SqlConnection connection = new SqlConnection(connectionString))
  120. {
  121. SqlCommand command = connection.CreateCommand();
  122. command.CommandText = commandText;
  123. command.Parameters.AddRange(parms);
  124. SqlDataAdapter adapter = new SqlDataAdapter(command);
  125. DataTable dt = new DataTable();
  126. adapter.Fill(dt);
  127.  
  128. return dt;
  129. }
  130. }
  131.  
  132. #endregion
  133. }
  134.  
  135. #region DbTable
  136. /// <summary>
  137. /// 表结构
  138. /// </summary>
  139. public sealed class DbTable
  140. {
  141. /// <summary>
  142. /// 表名称
  143. /// </summary>
  144. public string TableName { get; set; }
  145. /// <summary>
  146. /// 表的架构
  147. /// </summary>
  148. public string SchemaName { get; set; }
  149. /// <summary>
  150. /// 表的记录数
  151. /// </summary>
  152. public int Rows { get; set; }
  153.  
  154. /// <summary>
  155. /// 是否含有主键
  156. /// </summary>
  157. public bool HasPrimaryKey { get; set; }
  158. }
  159. #endregion
  160.  
  161. #region DbColumn
  162. /// <summary>
  163. /// 表字段结构
  164. /// </summary>
  165. public sealed class DbColumn
  166. {
  167. /// <summary>
  168. /// 字段ID
  169. /// </summary>
  170. public int ColumnID { get; set; }
  171.  
  172. /// <summary>
  173. /// 是否主键
  174. /// </summary>
  175. public bool IsPrimaryKey { get; set; }
  176.  
  177. /// <summary>
  178. /// 字段名称
  179. /// </summary>
  180. public string ColumnName { get; set; }
  181.  
  182. /// <summary>
  183. /// 字段类型
  184. /// </summary>
  185. public string ColumnType { get; set; }
  186.  
  187. /// <summary>
  188. /// 数据库类型对应的C#类型
  189. /// </summary>
  190. public string CSharpType
  191. {
  192. get
  193. {
  194. return SqlServerDbTypeMap.MapCsharpType(ColumnType);
  195. }
  196. }
  197.  
  198. /// <summary>
  199. ///
  200. /// </summary>
  201. public Type CommonType
  202. {
  203. get
  204. {
  205. return SqlServerDbTypeMap.MapCommonType(ColumnType);
  206. }
  207. }
  208.  
  209. /// <summary>
  210. /// 字节长度
  211. /// </summary>
  212. public int ByteLength { get; set; }
  213.  
  214. /// <summary>
  215. /// 字符长度
  216. /// </summary>
  217. public int CharLength { get; set; }
  218.  
  219. /// <summary>
  220. /// 小数位
  221. /// </summary>
  222. public int Scale { get; set; }
  223.  
  224. /// <summary>
  225. /// 是否自增列
  226. /// </summary>
  227. public bool IsIdentity { get; set; }
  228.  
  229. /// <summary>
  230. /// 是否允许空
  231. /// </summary>
  232. public bool IsNullable { get; set; }
  233.  
  234. /// <summary>
  235. /// 描述
  236. /// </summary>
  237. public string Remark { get; set; }
  238. }
  239. #endregion
  240.  
  241. #region SqlServerDbTypeMap
  242.  
  243. public class SqlServerDbTypeMap
  244. {
  245. public static string MapCsharpType(string dbtype)
  246. {
  247. if (string.IsNullOrEmpty(dbtype)) return dbtype;
  248. dbtype = dbtype.ToLower();
  249. string csharpType = "object";
  250. switch (dbtype)
  251. {
  252. case "bigint": csharpType = "long"; break;
  253. case "binary": csharpType = "byte[]"; break;
  254. case "bit": csharpType = "bool"; break;
  255. case "char": csharpType = "string"; break;
  256. case "date": csharpType = "DateTime"; break;
  257. case "datetime": csharpType = "DateTime"; break;
  258. case "datetime2": csharpType = "DateTime"; break;
  259. case "datetimeoffset": csharpType = "DateTimeOffset"; break;
  260. case "decimal": csharpType = "decimal"; break;
  261. case "float": csharpType = "double"; break;
  262. case "image": csharpType = "byte[]"; break;
  263. case "int": csharpType = "int"; break;
  264. case "money": csharpType = "decimal"; break;
  265. case "nchar": csharpType = "string"; break;
  266. case "ntext": csharpType = "string"; break;
  267. case "numeric": csharpType = "decimal"; break;
  268. case "nvarchar": csharpType = "string"; break;
  269. case "real": csharpType = "Single"; break;
  270. case "smalldatetime": csharpType = "DateTime"; break;
  271. case "smallint": csharpType = "short"; break;
  272. case "smallmoney": csharpType = "decimal"; break;
  273. case "sql_variant": csharpType = "object"; break;
  274. case "sysname": csharpType = "object"; break;
  275. case "text": csharpType = "string"; break;
  276. case "time": csharpType = "TimeSpan"; break;
  277. case "timestamp": csharpType = "byte[]"; break;
  278. case "tinyint": csharpType = "byte"; break;
  279. case "uniqueidentifier": csharpType = "Guid"; break;
  280. case "varbinary": csharpType = "byte[]"; break;
  281. case "varchar": csharpType = "string"; break;
  282. case "xml": csharpType = "string"; break;
  283. default: csharpType = "object"; break;
  284. }
  285. return csharpType;
  286. }
  287.  
  288. public static Type MapCommonType(string dbtype)
  289. {
  290. if (string.IsNullOrEmpty(dbtype)) return Type.Missing.GetType();
  291. dbtype = dbtype.ToLower();
  292. Type commonType = typeof(object);
  293. switch (dbtype)
  294. {
  295. case "bigint": commonType = typeof(long); break;
  296. case "binary": commonType = typeof(byte[]); break;
  297. case "bit": commonType = typeof(bool); break;
  298. case "char": commonType = typeof(string); break;
  299. case "date": commonType = typeof(DateTime); break;
  300. case "datetime": commonType = typeof(DateTime); break;
  301. case "datetime2": commonType = typeof(DateTime); break;
  302. case "datetimeoffset": commonType = typeof(DateTimeOffset); break;
  303. case "decimal": commonType = typeof(decimal); break;
  304. case "float": commonType = typeof(double); break;
  305. case "image": commonType = typeof(byte[]); break;
  306. case "int": commonType = typeof(int); break;
  307. case "money": commonType = typeof(decimal); break;
  308. case "nchar": commonType = typeof(string); break;
  309. case "ntext": commonType = typeof(string); break;
  310. case "numeric": commonType = typeof(decimal); break;
  311. case "nvarchar": commonType = typeof(string); break;
  312. case "real": commonType = typeof(Single); break;
  313. case "smalldatetime": commonType = typeof(DateTime); break;
  314. case "smallint": commonType = typeof(short); break;
  315. case "smallmoney": commonType = typeof(decimal); break;
  316. case "sql_variant": commonType = typeof(object); break;
  317. case "sysname": commonType = typeof(object); break;
  318. case "text": commonType = typeof(string); break;
  319. case "time": commonType = typeof(TimeSpan); break;
  320. case "timestamp": commonType = typeof(byte[]); break;
  321. case "tinyint": commonType = typeof(byte); break;
  322. case "uniqueidentifier": commonType = typeof(Guid); break;
  323. case "varbinary": commonType = typeof(byte[]); break;
  324. case "varchar": commonType = typeof(string); break;
  325. case "xml": commonType = typeof(string); break;
  326. default: commonType = typeof(object); break;
  327. }
  328. return commonType;
  329. }
  330. }
  331. #endregion
  332. #>

一次生成多个文件

Entity.tt

  1. <#@ template debug="false" hostspecific="true" language="C#" #>
  2. <#@ assembly name="System.Data" #>
  3. <#@ assembly name="System.xml" #>
  4. <#@ import namespace="System.Collections.Generic" #>
  5. <#@ import namespace="System.Data.SqlClient" #>
  6. <#@ import namespace="System.Data" #>
  7. <#@ assembly name="System.Core" #>
  8. <#@ import namespace="System.Linq" #>
  9.  
  10. // 导入MultipleOutputHelper.ttinclude文件
  11. <#@ include file="$(ProjectDir)MultipleOutputHelper.ttinclude" #>
  12.  
  13. <#
  14. string connectionString= "server=10.126.124.0;database=ZSOtherData;uid=it_zs;pwd=dev4ZS@2018;";
  15. SqlConnection conn = new SqlConnection(connectionString);
  16. conn.Open();
  17.  
  18. string selectQuery ="SET FMTONLY ON; select * from @tableName; SET FMTONLY OFF;";
  19. SqlCommand command = new SqlCommand(selectQuery,conn);
  20. SqlDataAdapter ad = new SqlDataAdapter(command);
  21. System.Data.DataSet ds = new DataSet();
  22.  
  23. var manager = Manager.Create(Host, GenerationEnvironment);
  24.  
  25. System.Data.DataTable schema = conn.GetSchema("Tables");
  26. foreach(System.Data.DataRow row in schema.Rows)
  27. {
  28. ds.Tables.Clear();
  29. string tb_name= row["TABLE_NAME"].ToString();
  30. command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString());
  31. ad.FillSchema(ds, SchemaType.Mapped,tb_name);
  32.  
  33. manager.StartNewFile(tb_name+".cs");#>
  34.  
  35. using System;
  36. using System.Collections.Generic;
  37. namespace MY.Model
  38. {
  39. /// <summary>
  40. /// 实体-<#=tb_name#>
  41. /// </summary>
  42. public partial class <#=tb_name#>
  43. {
  44. <#
  45. PushIndent(" ");
  46. foreach (DataColumn dc in ds.Tables[].Columns)
  47. {
  48. WriteLine("public " + dc.DataType.Name+ (dc.AllowDBNull && dc.DataType.Name.ToLower() != "string" ? "? ": " ") + dc.ColumnName + " { get; set; }");
  49. }
  50. PopIndent();
  51. #>
  52. }
  53. }
  54.  
  55. <#
  56. manager.EndBlock();
  57. }
  58. conn.Close();
  59. manager.Process(true);
  60. #>

Action.tt

  1. <#@ template debug="false" hostspecific="true" language="C#" #>
  2. <#@ assembly name="System.Data" #>
  3. <#@ assembly name="System.xml" #>
  4. <#@ import namespace="System.Collections.Generic" #>
  5. <#@ import namespace="System.Data.SqlClient" #>
  6. <#@ import namespace="System.Data" #>
  7. <#@ assembly name="System.Core" #>
  8. <#@ import namespace="System.Linq" #>
  9.  
  10. // 导入MultipleOutputHelper.ttinclude文件
  11. <#@ include file="$(ProjectDir)\MultipleOutputHelper.ttinclude" #>
  12. <#
  13. string connectionString= "server=10.126.124.0;database=ZSOtherData;uid=it_zs;pwd=dev4ZS@2018;";
  14. SqlConnection conn = new SqlConnection(connectionString);
  15. conn.Open();
  16.  
  17. string selectQuery ="SET FMTONLY ON; select * from @tableName; SET FMTONLY OFF;";
  18. SqlCommand command = new SqlCommand(selectQuery,conn);
  19. SqlDataAdapter ad = new SqlDataAdapter(command);
  20. System.Data.DataSet ds = new DataSet();
  21.  
  22. var manager = Manager.Create(Host, GenerationEnvironment);
  23.  
  24. System.Data.DataTable schema = conn.GetSchema("Tables");
  25. foreach(System.Data.DataRow row in schema.Rows)
  26. {
  27. ds.Tables.Clear();
  28. string tb_name= row["TABLE_NAME"].ToString();
  29. command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString());
  30. ad.FillSchema(ds, SchemaType.Mapped,tb_name);
  31. manager.StartNewFile(tb_name+"Action.cs");#>
  32.  
  33. using System;
  34. using System.Collections.Generic;
  35. using MY.Model;
  36. namespace MY.BLL
  37. {
  38.  
  39. /// <summary>
  40. /// <#=tb_name#> 操作类
  41. /// </summary>
  42. public partial class <#=tb_name#>Action
  43. {<#
  44. string fkQuery = " SELECT f.name AS ForeignKey,";
  45. fkQuery += " OBJECT_NAME(f.parent_object_id) AS TableName, ";
  46. fkQuery += " COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName, ";
  47. fkQuery += " OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName, ";
  48. fkQuery += " COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName ";
  49. fkQuery += " FROM ";
  50. fkQuery += " sys.foreign_keys AS f ";
  51. fkQuery += " INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id ";
  52. fkQuery += " where OBJECT_NAME(f.parent_object_id) = '" +tb_name +"'";
  53.  
  54. List<string> fkColumnNames = new List<string>();
  55. Dictionary<string, string> parentTables = new Dictionary<string, string>();
  56.  
  57. SqlCommand command2 = new SqlCommand(fkQuery,conn);
  58. using(var dr = command2.ExecuteReader())
  59. {
  60. while(dr.Read())
  61. {
  62. fkColumnNames.Add(dr["ColumnName"].ToString());
  63. parentTables.Add(dr["ColumnName"].ToString(), dr["ReferenceTableName"].ToString());
  64. }
  65. dr.Close();
  66. }
  67.  
  68. List<DataColumn> fkColumns = new List<DataColumn>();
  69. foreach(string fkColumnName in fkColumnNames)
  70. {
  71. foreach (DataColumn dc in ds.Tables[].Columns)
  72. {
  73. if(dc.ColumnName == fkColumnName)
  74. fkColumns.Add(dc);
  75. }
  76. }
  77.  
  78. List<string> primaryKeyParamsWithTypes = new List<string>();
  79. List<string> primaryKeyParams = new List<string>();
  80. List<string> whereItems = new List<string>();
  81. List<string> automapItems = new List<string>();
  82. foreach(DataColumn pk in ds.Tables[].PrimaryKey)
  83. {
  84. primaryKeyParamsWithTypes.Add(string.Format("{0} {1}", pk.DataType.Name, this.ToCamelCase(pk.ColumnName)));
  85. primaryKeyParams.Add(pk.ColumnName);
  86. whereItems.Add(string.Format("{0} = @{1}", pk.ColumnName, pk.ColumnName.ToLower()));
  87. automapItems.Add(string.Format("x.{0}", pk.ColumnName));
  88. }
  89.  
  90. string updateAutomap = string.Empty;
  91. if(automapItems.Count > ){
  92. if(automapItems.Count > )
  93. updateAutomap = "new { " + string.Join(", ", automapItems.ToArray()) + " }";
  94. else
  95. updateAutomap = automapItems[];
  96. }
  97. #>
  98.  
  99. public static <#=tb_name#> Select(<#=string.Join(", ", primaryKeyParamsWithTypes.ToArray())#>)
  100. {
  101. using(var context = db.Context())
  102. {
  103. return context.Sql(" SELECT * FROM <#=tb_name#> WHERE <#=string.Join(" AND ", whereItems.ToArray())#> ")
  104. <#foreach(string pkp in primaryKeyParams)
  105. {
  106. WriteLine(".Parameter(\"" + pkp.ToLower() + "\", " + this.ToCamelCase(pkp) + ")");
  107. }
  108. #>
  109. .QuerySingle<<#=tb_name#>>();
  110. }
  111. }
  112.  
  113. public static List<<#=tb_name#>> SelectAll()
  114. {
  115. return SelectAll(string.Empty);
  116. }
  117.  
  118. public static List<<#=tb_name#>> SelectAll(string sortExpression)
  119. {
  120. return SelectAll(, , sortExpression);
  121. }
  122.  
  123. public static List<<#=tb_name#>> SelectAll(int startRowIndex, int maximumRows, string sortExpression)
  124. {
  125. using (var context = db.Context())
  126. {
  127. var select = context.Select<<#=tb_name#>>(" * ")
  128. .From(" <#=tb_name#> ");
  129.  
  130. if (maximumRows > )
  131. {
  132. if (startRowIndex == )
  133. startRowIndex = ;
  134.  
  135. select.Paging(startRowIndex, maximumRows);
  136. }
  137.  
  138. if (!string.IsNullOrEmpty(sortExpression))
  139. select.OrderBy(sortExpression);
  140.  
  141. return select.QueryMany();
  142. }
  143. }
  144.  
  145. public static int CountAll()
  146. {
  147. using (var context = db.Context())
  148. {
  149. return context.Sql(" SELECT COUNT(*) FROM <#=tb_name#> ")
  150. .QuerySingle<int>();
  151. }
  152. }
  153.  
  154. <#
  155. foreach(DataColumn dc in fkColumns)
  156. {
  157. #>
  158.  
  159. public static List<<#=tb_name#>> SelectBy<#=parentTables[dc.ColumnName]#>(<#=dc.DataType.Name#> <#=this.ToCamelCase(dc.ColumnName)#>)
  160. {
  161. return SelectBy<#=parentTables[dc.ColumnName]#>(<#=this.ToCamelCase(dc.ColumnName)#>, string.Empty);
  162. }
  163.  
  164. public static List<<#=tb_name#>> SelectBy<#=parentTables[dc.ColumnName]#>(<#=dc.DataType.Name#> <#=this.ToCamelCase(dc.ColumnName)#>, string sortExpression)
  165. {
  166. return SelectBy<#=parentTables[dc.ColumnName]#>(<#=this.ToCamelCase(dc.ColumnName)#>, , , sortExpression);
  167. }
  168.  
  169. public static List<<#=tb_name#>> SelectBy<#=parentTables[dc.ColumnName]#>(<#=dc.DataType.Name#> <#=this.ToCamelCase(dc.ColumnName)#>, int startRowIndex, int maximumRows, string sortExpression)
  170. {
  171. using (var context = db.Context())
  172. {
  173. var select = context.Select<<#=tb_name#>>(" * ")
  174. .From(" <#=tb_name#> ")
  175. .Where(" <#=dc.ColumnName#> = @<#=dc.ColumnName.ToLower()#> ")
  176. .Parameter("<#=dc.ColumnName.ToLower()#>", <#=this.ToCamelCase(dc.ColumnName)#>);
  177.  
  178. if (maximumRows > )
  179. {
  180. if (startRowIndex == )
  181. startRowIndex = ;
  182.  
  183. select.Paging(startRowIndex, maximumRows);
  184. }
  185.  
  186. if (!string.IsNullOrEmpty(sortExpression))
  187. select.OrderBy(sortExpression);
  188.  
  189. return select.QueryMany();
  190. }
  191. }
  192.  
  193. public static int CountBy<#=parentTables[dc.ColumnName]#>(<#=dc.DataType.Name#> <#=this.ToCamelCase(dc.ColumnName)#>)
  194. {
  195. using (var context = db.Context())
  196. {
  197. return context.Sql(" SELECT COUNT(*) FROM <#=tb_name#> WHERE <#=dc.ColumnName#> = @<#=dc.ColumnName.ToLower()#>")
  198. .Parameter("<#=dc.ColumnName.ToLower()#>", <#=this.ToCamelCase(dc.ColumnName)#>)
  199. .QuerySingle<int>();
  200. }
  201. }
  202. <#}#>
  203.  
  204. <#if(ds.Tables[0].PrimaryKey != null && ds.Tables[0].PrimaryKey.Length == 1 && ds.Tables[0].PrimaryKey[0].AutoIncrement) {#>
  205. public static bool Insert(<#=tb_name#> <#=this.ToCamelCase(tb_name)#>)
  206. {
  207. using (var context = db.Context())
  208. {
  209. int id = context.Insert<<#=tb_name#>>("<#=tb_name#>", <#=this.ToCamelCase(tb_name)#>)
  210. .AutoMap(x => x.<#=primaryKeyParams[]#>)
  211. .ExecuteReturnLastId<int>();
  212.  
  213. <#=this.ToCamelCase(tb_name)#>.<#=primaryKeyParams[]#> = id;
  214. return id > ;
  215. }
  216. }
  217. <#
  218. }
  219. else
  220. {
  221. #>
  222. public static bool Insert(<#=tb_name#> <#=this.ToCamelCase(tb_name)#>)
  223. {
  224. using (var context =db.Context())
  225. {
  226. return context.Insert<<#=tb_name#>>("<#=tb_name#>", <#=this.ToCamelCase(tb_name)#>)
  227. .Execute() > ;
  228. }
  229. }
  230. <#}#>
  231. public static bool Update(<#=tb_name#> <#=this.ToCamelCase(tb_name)#>)
  232. {
  233. using (var context = db.Context())
  234. {
  235. return context.Update<<#=tb_name#>>("<#=tb_name#>", <#=this.ToCamelCase(tb_name)#>)
  236. .AutoMap(x => <#=updateAutomap#>)
  237. <#foreach(string pkp in primaryKeyParams){#>
  238. .Where("<#=pkp#>", <#=this.ToCamelCase(tb_name)#>.<#=pkp#>)
  239. <#}#>
  240. .Execute() > ;
  241. }
  242. }
  243.  
  244. public static bool Delete(<#=tb_name#> <#=this.ToCamelCase(tb_name)#>)
  245. {
  246. return Delete(<#=string.Join(", ", primaryKeyParams.Select(x=> this.ToCamelCase(tb_name) + "." + x).ToArray())#>);
  247. }
  248.  
  249. public static bool Delete(<#=string.Join(", ", primaryKeyParamsWithTypes.ToArray())#>)
  250. {
  251. using (var context = db.Context())
  252. {
  253. return context.Sql(" DELETE FROM Product WHERE <#=string.Join(" AND ", whereItems.ToArray())#> ")
  254. <#foreach(string pkp in primaryKeyParams) {
  255. WriteLine(".Parameter(\"" + pkp.ToLower() + "\", " + this.ToCamelCase(pkp) + ")");
  256. }#>
  257. .Execute() > ;
  258. }
  259. }
  260. }
  261.  
  262. }
  263.  
  264. <#
  265. manager.EndBlock();
  266. }
  267. conn.Close();
  268. manager.Process(true);
  269. #>
  270.  
  271. <#+
  272. public string ToCamelCase(string value)
  273. {
  274. if(string.IsNullOrEmpty(value))
  275. return string.Empty;
  276.  
  277. string firstLetter = value.Substring(, );
  278. string rest = value.Substring(, value.Length - );
  279. return firstLetter.ToLower() + rest;
  280. }
  281. #>

MultipleOutputHelper.ttinclude

  1. <#@ assembly name="System.Core"
  2. #><#@ assembly name="System.Data.Linq"
  3. #><#@ assembly name="EnvDTE"
  4. #><#@ assembly name="System.Xml"
  5. #><#@ assembly name="System.Xml.Linq"
  6. #><#@ import namespace="System"
  7. #><#@ import namespace="System.CodeDom"
  8. #><#@ import namespace="System.CodeDom.Compiler"
  9. #><#@ import namespace="System.Collections.Generic"
  10. #><#@ import namespace="System.Data.Linq"
  11. #><#@ import namespace="System.Data.Linq.Mapping"
  12. #><#@ import namespace="System.IO"
  13. #><#@ import namespace="System.Linq"
  14. #><#@ import namespace="System.Reflection"
  15. #><#@ import namespace="System.Text"
  16. #><#@ import namespace="System.Xml.Linq"
  17. #><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
  18. #><#+
  19.  
  20. // Manager class records the various blocks so it can split them up
  21. class Manager {
  22. private class Block {
  23. public String Name;
  24. public int Start, Length;
  25. public bool IncludeInDefault;
  26. }
  27.  
  28. private Block currentBlock;
  29. private List<Block> files = new List<Block>();
  30. private Block footer = new Block();
  31. private Block header = new Block();
  32. private ITextTemplatingEngineHost host;
  33. private StringBuilder template;
  34. protected List<String> generatedFileNames = new List<String>();
  35.  
  36. public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
  37. return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
  38. }
  39.  
  40. public void StartNewFile(String name) {
  41. if (name == null)
  42. throw new ArgumentNullException("name");
  43. CurrentBlock = new Block { Name = name };
  44. }
  45.  
  46. public void StartFooter(bool includeInDefault = true) {
  47. CurrentBlock = footer;
  48. footer.IncludeInDefault = includeInDefault;
  49. }
  50.  
  51. public void StartHeader(bool includeInDefault = true) {
  52. CurrentBlock = header;
  53. header.IncludeInDefault = includeInDefault;
  54. }
  55.  
  56. public void EndBlock() {
  57. if (CurrentBlock == null)
  58. return;
  59. CurrentBlock.Length = template.Length - CurrentBlock.Start;
  60. if (CurrentBlock != header && CurrentBlock != footer)
  61. files.Add(CurrentBlock);
  62. currentBlock = null;
  63. }
  64.  
  65. public virtual void Process(bool split, bool sync = true) {
  66. if (split) {
  67. EndBlock();
  68. String headerText = template.ToString(header.Start, header.Length);
  69. String footerText = template.ToString(footer.Start, footer.Length);
  70. String outputPath = Path.GetDirectoryName(host.TemplateFile);
  71. files.Reverse();
  72. if (!footer.IncludeInDefault)
  73. template.Remove(footer.Start, footer.Length);
  74. foreach(Block block in files) {
  75. String fileName = Path.Combine(outputPath, block.Name);
  76. String content = headerText + template.ToString(block.Start, block.Length) + footerText;
  77. generatedFileNames.Add(fileName);
  78. CreateFile(fileName, content);
  79. template.Remove(block.Start, block.Length);
  80. }
  81. if (!header.IncludeInDefault)
  82. template.Remove(header.Start, header.Length);
  83. }
  84. }
  85.  
  86. protected virtual void CreateFile(String fileName, String content) {
  87. if (IsFileContentDifferent(fileName, content))
  88. File.WriteAllText(fileName, content);
  89. }
  90.  
  91. public virtual String GetCustomToolNamespace(String fileName) {
  92. return null;
  93. }
  94.  
  95. public virtual String DefaultProjectNamespace {
  96. get { return null; }
  97. }
  98.  
  99. protected bool IsFileContentDifferent(String fileName, String newContent) {
  100. return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
  101. }
  102.  
  103. private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
  104. this.host = host;
  105. this.template = template;
  106. }
  107.  
  108. private Block CurrentBlock {
  109. get { return currentBlock; }
  110. set {
  111. if (CurrentBlock != null)
  112. EndBlock();
  113. if (value != null)
  114. value.Start = template.Length;
  115. currentBlock = value;
  116. }
  117. }
  118.  
  119. private class VSManager: Manager {
  120. private EnvDTE.ProjectItem templateProjectItem;
  121. private EnvDTE.DTE dte;
  122. private Action<String> checkOutAction;
  123. private Action<IEnumerable<String>> projectSyncAction;
  124.  
  125. public override String DefaultProjectNamespace {
  126. get {
  127. return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
  128. }
  129. }
  130.  
  131. public override String GetCustomToolNamespace(string fileName) {
  132. return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
  133. }
  134.  
  135. public override void Process(bool split, bool sync) {
  136. if (templateProjectItem.ProjectItems == null)
  137. return;
  138. base.Process(split, sync);
  139. if (sync)
  140. projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
  141. }
  142.  
  143. protected override void CreateFile(String fileName, String content) {
  144. if (IsFileContentDifferent(fileName, content)) {
  145. CheckoutFileIfRequired(fileName);
  146. File.WriteAllText(fileName, content);
  147. }
  148. }
  149.  
  150. internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
  151. : base(host, template) {
  152. var hostServiceProvider = (IServiceProvider) host;
  153. if (hostServiceProvider == null)
  154. throw new ArgumentNullException("Could not obtain IServiceProvider");
  155. dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
  156. if (dte == null)
  157. throw new ArgumentNullException("Could not obtain DTE from host");
  158. templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
  159. checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
  160. projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
  161. }
  162.  
  163. private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
  164. var keepFileNameSet = new HashSet<String>(keepFileNames);
  165. var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
  166. var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames()) + ".";
  167. foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
  168. projectFiles.Add(projectItem.get_FileNames(), projectItem);
  169.  
  170. // Remove unused items from the project
  171. foreach(var pair in projectFiles)
  172. if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
  173. pair.Value.Delete();
  174.  
  175. // Add missing files to the project
  176. foreach(String fileName in keepFileNameSet)
  177. if (!projectFiles.ContainsKey(fileName))
  178. templateProjectItem.ProjectItems.AddFromFile(fileName);
  179. }
  180.  
  181. private void CheckoutFileIfRequired(String fileName) {
  182. var sc = dte.SourceControl;
  183. if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
  184. checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
  185. }
  186. }
  187. } #>

T4学习- 2、创建设计时模板的更多相关文章

  1. T4学习- 3、创建运行时模板

    使用 Visual Studio 预处理过的文本模板,可以在运行时在应用程序中生成文本字符串. 执行应用程序的计算机不必具有 Visual Studio. 预处理过的模板有时称为"运行时文本 ...

  2. T4设计时模板调试

    在Visual Studio内调试T4设计时模板有多个方法:安装使用带调试功能的第三方工具,利用System.Diagnostics.Debugger实时调试器,VS内置的T4调试工具.使用第三方工具 ...

  3. T4学习- 1、简介

    一.T4简介       T4(Text Template Transformation Toolkit)在 Visual Studio 中,"T4 文本模板"是由一些文本块和控制 ...

  4. 使用 T4 文本模板生成设计时代码

      使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件. 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码. 模型是包含有关应用程序要求的 ...

  5. 设计时数据源:在PostgreSql 数据查询中使用参数过滤

    在上一篇文章中,我们学习了如何设计时连接PostgreSQL 数据库及环境搭建.本节我们来学习使用PostgreSql 数据源时,创建数据集时带参数过滤的查询语句写法. 在报表中包含两种参数,可参考博 ...

  6. T4运行时模板

    可以通过Visual Studio运行时文本模板在您的应用程序在运行时生成文本字符串. 执行应用程序的计算机不必具有 Visual Studio. 运行库模板有时称为"预处理文本模板&quo ...

  7. 一、数据库表中字段的增删改查,二、路由基础.三、有名无名分组.四、多app共存的路由分配.五、多app共存时模板冲突问题.六、创建app流程.七、路由分发.八、路由别名,九、名称空间.十、反向解析.十一、2.x新特性.十二、自定义转换器

    一.数据库表中字段的增删改查 ''' 直接在modules中对字段进行增删改查 然后在tools下点击Run manage.py Task执行makemigrations和migrate 注意在执行字 ...

  8. mysql 创建表时注意事项

    mysql  创建表时注意事项 mysql 想必大家都不会陌生吧  是我学习中第一个接触的的数据库 已学习就很快上手的   这是一个关系型数据库  不懂什么是关系型数据库 啊哈哈哈  现在知道啦  因 ...

  9. 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效

    数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...

随机推荐

  1. Spring @ModelAttribute

    正文开始之前,先介绍个东西,Spring能够自动将请求参数封装到对应JavaBean上! 代码比较简单,也没有什么配置要记录,只是开启了<mvc:annotation-driven/>,可 ...

  2. No caching ——无缓存工具

    No caching ——无缓存工具 无缓存工具阻止客户端应用程序(如Web浏览器)缓存任何资源,因此,请求总是发送到远程站点,所以我们总能看到最新版本. 适用场景 开发每次新部署了一版环境,说解决了 ...

  3. 附件十四面3D模型的自动化生成

    附件十四面的3D模型可以自动生成了 2017-10-14 刘崇军 风螺旋线 这个故事开始于大约半年前,偶然从电脑里翻到了曾经收藏的这本书<Automatic SketchUp>,英语+3D ...

  4. 异步上传文件,jquery+ajax,显示进度条

    根据网上的资料,做了很多修改,结果发现使用ajax上传数据时若要监听xhr.upload.addEventListener("progress",functiion(e),fals ...

  5. Http请求帮助类

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...

  6. leetcode916

    单词子集 我们给出两个单词数组 A 和 B.每个单词都是一串小写字母. 现在,如果 b 中的每个字母都出现在 a 中,包括重复出现的字母,那么称单词 b是单词 a 的子集. 例如,“wrr” 是 “w ...

  7. centos7: ifconfig出现command not found解决办法

    问题 说下我linux配置情况,不一样的可以选择借鉴我的办法. 在虚拟机中以最小化方式安装centos7,ifconfig命令无效,而且在sbin目录中没有ifconfig文件. 原因 这是因为cen ...

  8. Android四大组件framework层

    activity https://www.kancloud.cn/alex_wsc/android-deep2/413484 当前Activity Activity向AMS发送StartActivit ...

  9. H5 页面下拉加载更多

    1.html页面: <body onload="index_roll()"> ... </body> 2.js <script type=" ...

  10. nginx禁止ip默认参数是$remote_addr无法禁止真实ip的问题

    由于网站使用了cdn所以$remote_addr获取的ip是cdn的ip,我现在先禁止某些ip访问发现无法禁止cdn传递过来的客户端的ip也就是$http_x_forwarded_for这个参数.比如 ...