介紹如何使用LinqPad產生相對應的Input和Result的DTO
前言
目前的專案因為是全部使用sp的方式,所以專案使用了目前最火的dapper來做,但dapper需要類別的對應,針對一堆table還有sp的類別建立,其實也是非常費工,已經有mrkt大師介紹過了,如何使用table產生相對應的dto,雖然真的很方便,但sp的input和output呢?這篇則是來說明一下如何使用LinqPad來產生SP的相對應類別。
大綱
- 目的
- 產生SP的input的類別
- 產生SP的result的類別
- 總結
1.目的
其實產生table或sp的result相對應的類別,對我來說吸引力並不是很大,因為如果我們用entity來做db first的方式,已經可以產生table和sp的result類別了,但是input怎麼辦呢?我們來看一下entity產出的相關類別吧,以一個table的專案來做示例。
下圖是table的
下圖則是entity產生的sp對應的類別,首先是Result,看來挺ok的
下圖則是input的參數,好像沒辦法直接複製貼上轉成對應的類別耶
難不成如果input有四十個欄位,我只能一個一個copy嗎?只好google大神了,只要有現成工具,絕對不自己造輪子,因為經過眾人試驗的工具,相信issue也會被修正的差不多,但我卻好像也找不著有類似的做法,最後為了追求工程師極致的美德,也就是如下圖這個字
最後只好自己研究來造輪子了,接著就說明一下囉。
2.產生SP的input的類別
其實也是沿用了原本大神的table產生的類別,然後再改造一下,變成了我最需要的產生sp的input的類別,可以看到LinqPad的圖示例
完美的產生了Input的語法,一切就是那麼的美好,複製貼上就完成了一個類別的對應,頂多是改改sp的名稱,沒code沒真相,以下是在linq pad上的原始碼
void Main()
{
this.Connection.DumpInput("select * from INFORMATION_SCHEMA.PARAMETERS where specific_name = 'usp_EHR_ACTIVITY_SAVE'", "usp_EHR_ACTIVITY_SAVEDto").Dump();
}
public static class LINQPadExtensions
{
public static string DumpInput(this IDbConnection connection, string sql, string spName)
{
if (connection.State != ConnectionState.Open)
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = sql;
using (var reader = cmd.ExecuteReader())
{
string typeName = string.Empty;
string columnName = string.Empty;
var builder = new StringBuilder();
builder.AppendLine($"public class {spName}");
builder.AppendLine("{");
while (reader.Read())
{
typeName = ConvertTypeToCsharp(reader["DATA_TYPE"].ToString());
columnName = reader["PARAMETER_NAME"].ToString();
columnName = columnName.Replace('@', ' ');
builder.AppendLine(string.Format("\tpublic {0} {1} {{get; set;}}", typeName, columnName));
}
builder.AppendLine("}");
builder.AppendLine();
return builder.ToString();
}
}
private static string ConvertTypeToCsharp(string type)
{
var lowerType = type.ToLower();
if (lowerType == "int") return "int";
if (lowerType == "smallint") return "short";
if (lowerType == "bigint") return "long";
if (lowerType == "tinyint") return "byte";
if (lowerType == "binary") return "byte[]";
if (lowerType.Contains("char") || lowerType.Contains("text")) return "string";
if (lowerType.Contains("date")) return "DateTime";
if (lowerType.Contains("decimal") || lowerType.Contains("numeric")) return "decimal";
if (lowerType == "float") return lowerType;
if (lowerType.Contains("money")) return "double";
if (lowerType == "bit") return "bool";
return null;
}
}
3.產生SP的result的類別
雖然Entity預設已經能幫忙產生Result的類別,但每次都要去更新entity也是挺麻煩的,所以乾脆再來做一個sp的result吧,圖示如下。
一樣沒code沒真相的概念,以下則是result的原始碼,一樣copy去linq pad改改您的sp名稱,就能取得result的類別對應。
void Main()
{
this.Connection.DumpResult("SELECT * FROM sys.dm_exec_describe_first_result_set_for_object(OBJECT_ID('usp_EHR_NOTIFY_SAMPLE_GET_BY_SERIL_NO'),NULL)", "usp_EHR_ACTIVITY_GET_BY_ACTIVITY_TYPE_SERIL_NOResultDto").Dump();
}
public static class LINQPadExtensions
{
public static string DumpResult(this IDbConnection connection, string sql, string spName)
{
if (connection.State != ConnectionState.Open)
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = sql;
using (var reader = cmd.ExecuteReader())
{
string typeName = string.Empty;
string columnName = string.Empty;
var builder = new StringBuilder();
builder.AppendLine($"public class {spName}");
builder.AppendLine("{");
while (reader.Read())
{
typeName = ConvertTypeToCsharp(reader["system_type_name"].ToString());
columnName = reader["name"].ToString();
columnName = columnName.Replace('@', ' ');
builder.AppendLine(string.Format("\tpublic {0} {1} {{get; set;}}", typeName, columnName));
}
builder.AppendLine("}");
builder.AppendLine();
return builder.ToString();
}
}
private static string ConvertTypeToCsharp(string type)
{
var lowerType = type.ToLower();
if (lowerType == "int") return "int";
if (lowerType == "smallint") return "short";
if (lowerType == "bigint") return "long";
if (lowerType == "tinyint") return "byte";
if (lowerType == "binary") return "byte[]";
if (lowerType.Contains("char") || lowerType.Contains("text")) return "string";
if (lowerType.Contains("date")) return "DateTime";
if (lowerType.Contains("decimal") || lowerType.Contains("numeric")) return "decimal";
if (lowerType == "float") return lowerType;
if (lowerType.Contains("money")) return "double";
if (lowerType == "bit") return "bool";
return null;
}
}
4.總結
雖然可以在LINQPAD上面直接產生類別是很方便,但並不是每個人都有裝LINQPAD也不是每個人會使用,而且為了讓團隊可以方便使用,我乾脆就直接寫成一個網站,然後放在區網供團隊成員方便產生相對應的類別,這個網站是用mvc6+angularjs做的,因為一切都是用nuget下載的,所以就不用擔心任何前端套件的問題了,另外再加上自動產生Insert和Update的sp語法,對我來說這也足夠了,最後提供上GITHUB連結,希望幫助到有使用的團隊。
https://github.com/kinanson/mssql-generate-poco