[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 也要設定喔,如下圖所示:
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 時,應針對註解的關鍵字進行搜尋,以確保只有自動產生的檔案會略過檢查。
參考資源
- Exclude file from StyleCop analysis - “auto-generated” tag is ignored
- StyleCop: How To Ignore Generated Code
blog 與課程更新內容,請前往新站位置:http://tdd.best/