[Tool][Memo]如何讓 StyleCop 略過自動產生的檔案

  • 3759
  • 0
  • 2013-03-28

[Tool][Memo]如何讓 StyleCop 略過自動產生的檔案

前言

先前提過,如何使用 T4 的 template 檔案,來產生 DB table 對應的 Entity 。請見:[.NET]透過 T4 產生對應 DB Table 的 Entity

然而因為 DB table 與 column 的命名可能有些歷史包袱,加上 naming rule 的最大重點就是一致性。因此,產生出來的 entity 會不符合 StyleCop 的 naming rule 。

不只是 column 與 table 的命名,包含型別別名的部分,可能也會被 StyleCop 抓出來鞭,除非採用黑大的 solution : CODE-自動產生程式碼時將System.Int32轉為int

如果因為自動產生的檔案,導致 CI server 上 StyleCop 報表失真,那對團隊也是一種困擾。因此,這一篇文章介紹一個簡單的方式,避免 StyleCop 檢查自動產生的檔案。

 

Solution

解決方式其實超級超級簡單,只要在自動產生的檔案開頭加上一行註解:


// <auto-generated />

這樣 StyleCop 就會略過這個檔案不檢查了。以我這邊的例子,就是直接加入 T4 的範本檔開頭就可以了。

參考的文章裡面是提到,檔案中只要有這行註解即可,不過我自己的測試是,一定要加在開頭的第一行,否則還是會檢查。

另外也要記得 StyleCop 的 Setting 也要設定喔,如下圖所示:

image

 

Sample:


<#@ template language="C#" debug="True" hostspecific="True" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Data.DataSetExtensions" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Linq" #>
// <auto-generated />

using System;

namespace MyProject.Entities
{        
		<#  //修改connection string
			string connectionString = "你的connectionstring"; 
			
			SqlConnection conn = new SqlConnection(connectionString); 
			conn.Open(); 
			
			var tableName = "你的table名稱";

			//如果需要database中全部table,則使用conn.GetSchema("Tables")即可
			string[] restrictions = new string[4];
			restrictions[1] = "dbo";
			//修改table名稱
			restrictions[2] = tableName;
			DataTable schema = conn.GetSchema("Tables", restrictions);
			
			string selectQuery = @"
			SELECT top 1 * from  @tableName WITH(nolock);

			SELECT  	c.name AS [column],    		
						cd.value AS [column_desc],    		
						c.isnullable AS [isNullable]   		    		
			FROM    	sysobjects t WITH(nolock)
			INNER JOIN  syscolumns c WITH(nolock)
				ON		c.id = t.id
			LEFT OUTER JOIN sys.extended_properties cd WITH(nolock)
				ON		cd.major_id = c.id
				AND		cd.minor_id = c.colid
				AND		cd.name = 'MS_Description'
			WHERE t.type = 'u'
			and t.name='@tableName'
			ORDER BY    t.name, c.colorder;

			SELECT	top 1 
					t.name AS [table_name],
					td.value AS [table_desc]
			FROM    	sysobjects t WITH(nolock)
			INNER JOIN sys.extended_properties td WITH(nolock)
				ON		td.major_id = t.id
				AND 	td.minor_id = 0
				AND		td.name = 'MS_Description'
			WHERE t.type = 'u'
			and t.name='@tableName';"; 

			SqlCommand command = new SqlCommand(selectQuery,conn); 
			SqlDataAdapter ad = new SqlDataAdapter(command); 
			System.Data.DataSet ds = new DataSet(); 						

			foreach(System.Data.DataRow row in schema.Rows) 
			{ 				
				command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); 
				ad.Fill(ds);

				var isExistData = ds.Tables[2].Rows.Count > 0 ;
				var tableDescription = isExistData ? ds.Tables[2].Rows[0]["table_desc"].ToString() : "";				
			#>             						
			/// <summary>			
			/// <#= tableDescription #>
			/// mapping table name: <#= row["TABLE_NAME"].ToString() #>
			/// </summary>
			public class <#= row["TABLE_NAME"].ToString() #>                            
			{
				<#                 										
					foreach (DataColumn dc in ds.Tables[0].Columns)
					{					
						//string columnDescription = ds.Tables[1].AsEnumerable().Where(x => x["column"].ToString() == dc.ColumnName).Select(x => x["column_desc"].ToString()).FirstOrDefault();						
						var columnDefinition = ds.Tables[1].AsEnumerable().Where(x => x["column"].ToString() == dc.ColumnName).FirstOrDefault();						
						var columnDescription = columnDefinition["column_desc"].ToString();
						var isAllowNull = columnDefinition["isNullable"].ToString() == "1";
				#>
/// <summary>
				/// <#= columnDescription #>
				/// </summary>
				[ColumnMappingAttribute("<#= dc.ColumnName #>")]                        
				<# if(isAllowNull && dc.DataType.Name != "String"){ #>
public Nullable<<#= dc.DataType.Name #>> <#= dc.ColumnName #>  { get; set; }                                        
				<#     }                
				else
				{ #>
public <#= dc.DataType.Name #> <#= dc.ColumnName #>  { get; set; }
				<#}
				#>                            	
				<#    }                 #>                                
			}                            
<#    
			}  
			conn.Close();			
#>
}

為避免其他開發成員魚目混珠、暗渡陳倉,建議在 code review 時,應針對註解的關鍵字進行搜尋,以確保只有自動產生的檔案會略過檢查。

參考資源

  1. Exclude file from StyleCop analysis - “auto-generated” tag is ignored
  2. StyleCop: How To Ignore Generated Code

blog 與課程更新內容,請前往新站位置:http://tdd.best/