c# - 简单 POCO 的简单 T4 生成

标签 c# sql-server t4

<分区>

我正在寻找可以为一些 SQL Server 表生成简单 POCO 以在 ASP.NET MVC 中使用的教程、指南或软件。像这样:

1) 保留 SQL Server 数据库中应该生成 POCO 的表名列表

2) 将列表提供给某个程序

3) 该程序在单个 .cs 文件中生成一个简单的 POCO(更像 DTO),或附加到 Poco.cs。无论哪种方式,都没有关系。

例如:

public class MyDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool? IsMale {get; set;}
}

4) 每当我想重新生成 POCO 时运行程序

该程序可以是 WinForm、命令行或其他程序。没关系。

最佳答案

我一直想回答这个问题,但一直很忙。

我创建了一个关于如何读取数据库模式并从中生成类和属性的简单示例。

基本上,您应该能够将其剪切并粘贴到 TT 文件中(参见 Oleg Sychs blog 如何开始),更新连接字符串并保存以执行模板。

我并不是说这是一个完整的示例,但它可以作为您的起点:

  <#@ template   language    = "C#"                           #>
  <#@ assembly   name        = "Microsoft.CSharp"             #>
  <#@ assembly   name        = "System.Core"                  #>
  <#@ assembly   name        = "System.Data"                  #>
  <#@ import     namespace   = "System.Collections.Generic"   #>
  <#@ import     namespace   = "System.Dynamic"               #>
  <#@ import     namespace   = "System.Linq"                  #>
  <#@ import     namespace   = "System.Data.SqlClient"        #>

  <#
     var namespaceName    = "Poco2";
     // Update the connection string to something appropriate
     var connectionString = @"Data Source=localhost\SQLExpress;Initial Catalog=MyTest;Integrated Security=True";
  #>

  <#
     using (var db = new SqlConnection (connectionString))
     using (var cmd = db.CreateCommand ())
     {
        db.Open();
        var tables              = ReadRows (cmd, "SELECT * FROM sys.tables").ToArray ();

        var columns             = ReadRows (cmd, "SELECT * FROM sys.columns").ToLookup (k => k.object_id);

        var indexes             = ReadRows (cmd, "SELECT * FROM sys.indexes").ToLookup (k => k.object_id);
        var indexColumns        = ReadRows (cmd, "SELECT * FROM sys.index_columns").ToLookup (k => k.object_id);

        var foreignKeys         = ReadRows (cmd, "SELECT * FROM sys.foreign_keys").ToArray ();
        var foreignKeyColumns   = ReadRows (cmd, "SELECT * FROM sys.foreign_key_columns").ToArray ();
  #>
  namespace <#=namespaceName#>
  {
     using System;
     using System.Data.Linq.Mapping;

  <#
        foreach (var table in tables)
        {         
  #>
     [Table]
     partial class <#=table.name#>
     {
  <#
           IEnumerable<dynamic> tc = columns[table.object_id];
           var tableColumns = tc.OrderBy (r => r.column_id).ToArray ();          

           IEnumerable<dynamic> ti = indexes[table.object_id];
           var tableIndexes = ti.ToArray ();          

           var primaryKeyIndex = tableIndexes.FirstOrDefault (i => i.is_primary_key);
           var primaryKeyColumns = new Dictionary<dynamic, dynamic> ();
           if (primaryKeyIndex != null)
           {
              IEnumerable<dynamic> pc = indexColumns[table.object_id];
              primaryKeyColumns = pc
                 .Where (c => c.index_id == primaryKeyIndex.index_id)
                 .ToDictionary (c => c.column_id, c => c.key_ordinal)
                 ;
           }

           foreach (var tableColumn in tableColumns)
           {
              var type = MapToType (tableColumn.user_type_id, tableColumn.max_length, tableColumn.is_nullable);

  #>
        [Column (IsPrimaryKey = <#=primaryKeyColumns.ContainsKey (tableColumn.column_id) ? "true" : "false"#>)]
        public <#=type#> <#=tableColumn.name#> {get;set;}

  <#
           }
  #>

     }
  <#
        }
  #>
  }
  <#
     }
  #>

  <#+

     struct DataType
     {     
        public readonly int     SizeOf;
        public readonly string  SingularType;
        public readonly string  PluralType;

        public DataType (
           int sizeOf,
           string singularType,
           string pluralType = null
           )
        {
           SizeOf         = sizeOf;
           SingularType   = singularType;
           PluralType     = pluralType ?? (singularType + "[]");
        }

     }
     static Dictionary<int, DataType> dataTypes = new Dictionary<int, DataType>
        {
           {61   , new DataType (8,  "DateTime"            )},
           {127  , new DataType (8,  "long"                )},
           {165  , new DataType (1,  "byte"                )},
           {231  , new DataType (2,  "char"    ,  "string" )},
        };

     static string MapToType (int typeId, int maxLength, bool isNullable)
     {
        DataType dataType;

        if (dataTypes.TryGetValue (typeId, out dataType))
        {
           var length = maxLength > 0 ? (maxLength / dataType.SizeOf) : int.MaxValue;
           if (length > 1)
           {
              return dataType.PluralType;
           }
           else
           {
              return dataType.SingularType + (isNullable ? "?" : "");
           }
        }
        else
        {
           return "UnknownType_"+ typeId;
        }
     }

     static IEnumerable<dynamic> ReadRows (SqlCommand command, string sql)
     {
        command.CommandText = sql ?? "";

        using (var reader = command.ExecuteReader())
        {
           while (reader.Read())
           {
              var dyn = new ExpandoObject ();
              IDictionary<string, object> dic = dyn;

              for (var iter = 0; iter < reader.FieldCount; ++iter)
              {
                    dic[reader.GetName(iter) ?? ""] = reader.GetValue(iter);
              }

              yield return dyn;
           }

        }
     }


  #>

关于c# - 简单 POCO 的简单 T4 生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7919030/

相关文章:

c# - 8 位和 16 位整数的算术运算

c# - 在 C# 中使用补充 Unicode 字符作为 char 文字

mysql - 如何将 dbdeploy 与 SQL Server 一起使用?

sql-server - 赢得身份验证 NT 权限\匿名登录

c# - T4 引擎无法识别当前项目 namespace

c# - 如何让 CrystalReportViewer 在屏幕上居中?

c# - 路由上的约束条目 'httpMethod' 必须具有字符串值

c# - EF DateTimes 与 SQL Server 中保存的值不匹配

entity-framework - T4 和 Edmx 冲突 - "input file appears to be using a schema version not supported by this template"

entity-framework - 是否有使用 Fluent API 的 C# EF6 DbContext 生成器?