【LinqPad】透過LinqPad快速產生POCOs

看到twMVC#21的投影片,有一段很有興趣。

感謝,分享者(Kevin Tseng)的文章 Dapper - 使用 LINQPad 快速產生相對映 SQL Command 查詢結果的類別,完整記載著方法。

謝謝作者的提醒,我看到片段太興奮就沒看到簡報最終有分享此篇文章。

LinqPad是非常強大的工具,你有在寫Linq,我想應該會很依賴這工具。
PS:開發者非常的友善,有問必答。只要你敢寫信給他。

LinqPad我是使用付費版本,所以,若有功能你沒有,我想請你花錢支持作者。

其中,使用 LINQPad 快速產生 SQL Command 對映的類別 這功能我眼睛一亮。

我曾經寫過小工具,透過點一點選一選的方式產生Pocos物件,同時帶有驗證等。

不過,有些情況,譬如說列表清單的POCOs物件,其實,要的相對來說就很單純。

但是,要怎麼快速做出來POCOs物件呢!?

這邊提出的方案就是透過Linq的功能 + 自訂擴充屬性來完成。

首先,我在網路上找到已經有人分享如何處理。
原文章:Generate C# POCOs from SQL statement in LINQPad  By Necroskillz (沒想到,文章還沒寫完,已經得到作者允許直接貼程式碼了)。

以下程式碼擷取來源為該文章內容。


//Source From http://www.necronet.org/archive/2012/10/09/generate-c-pocos-from-sql-statement-in-linqpad.aspx/
public static class LINQPadExtensions
{
    private static readonly Dictionary<Type, string> TypeAliases = new Dictionary<Type, string> {
        { typeof(int), "int" },
        { typeof(short), "short" },
        { typeof(byte), "byte" },
        { typeof(byte[]), "byte[]" },
        { typeof(long), "long" },
        { typeof(double), "double" },
        { typeof(decimal), "decimal" },
        { typeof(float), "float" },
        { typeof(bool), "bool" },
        { typeof(string), "string" }
    };

    private static readonly HashSet<Type> NullableTypes = new HashSet<Type> {
        typeof(int),
        typeof(short),
        typeof(long),
        typeof(double),
        typeof(decimal),
        typeof(float),
        typeof(bool),
        typeof(DateTime)
    };

    public static string DumpClass(this IDbConnection connection, string sql)
    {
        if(connection.State != ConnectionState.Open)
            connection.Open();

        var cmd = connection.CreateCommand();
        cmd.CommandText = sql;
        var reader = cmd.ExecuteReader();

        var builder = new StringBuilder();
        do
        {
            if(reader.FieldCount <= 1) continue;

            builder.AppendLine("public class Info");
            builder.AppendLine("{");
            var schema = reader.GetSchemaTable();

            foreach (DataRow row in schema.Rows)
            {
                var type = (Type)row["DataType"];
                var name = TypeAliases.ContainsKey(type) ? TypeAliases[type] : type.Name;
                var isNullable = (bool)row["AllowDBNull"] && NullableTypes.Contains(type);
                var collumnName = (string)row["ColumnName"];

                builder.AppendLine(string.Format("\tpublic {0}{1} {2} ", name, isNullable ? "?" : string.Empty, collumnName));
            }

            builder.AppendLine("}");
            builder.AppendLine();            
        } while(reader.NextResult());

        return builder.ToString();
    }
}

你可以看到,將此程式貼上你Linq Pad 左下角打開的My Extensions。

打開以後,把原本所有的預設程式都刪除,將文章內的程式碼貼上。按下F5讓他進行編譯。

編譯以後,Linq 的Query選擇C# Program(很重要)。

因為該作者是透過擴充IDbConnection , 透過ExecuteReader來逐一讀取Select的欄位。

就文章內寫的除了一般Query,也可以處理Store Procedurs。

請注意,Select出來的一定要有欄位名稱唷!否則,屬性也會沒名字。

怎麼執行呢!?

因為該擴充屬性會回傳字串,所以,透過Console.Write輸出結果就好。

在Main區塊加入:

Console.WriteLine(this.Connection.DumpClass("Select * from Table"))

執行後,下方區塊就會依照寫的對應方法產生出POCO物件了。

public class Info
{
  public int Id 
  public string Name 
  public int? TCount 
}

很快速吧!不用自己一個一個Property打。

我個人建議可以調整程式的幾個地方:

  • 加一個參數Class Name
  • 不回傳字串物件,直接Console.Write輸出(這點好像就不夠物件導向XD)

想想,如果ViewModel要套驗證好像只能做到判斷Required。

所以,如果Model要套驗證歡迎大家試用我寫的工具,支援Sql Server & Oracle唷!!