简单的T4生成简单POCO

时间:2011-10-27 16:15:50

标签: c# sql-server t4

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

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,命令行或其他东西。没关系。

4 个答案:

答案 0 :(得分:8)

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

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

基本上你应该能够把它切成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;
           }

        }
     }


  #>

答案 1 :(得分:2)

我在大约1年前建立了一个类似的自定义生成工具,但我没有找到统一,全面的资源来实现这一目标。

Oleg Sych提供了许多关于在his blog使用T4的博客文章,并维护了一个库来帮助T4生成,T4 Toolbox。在开发过程中我非常依赖它们。

对于T4模板中的数据库模式发现,我使用了SQL Server Management Objects

我在Visual Studio中运行我的T4模板。

答案 2 :(得分:0)

你可以在亚音速3(在visual studio中运行)中使用classes.tt模板(在linqtemplates中加上SQLServer.ttinclude)。 http://subsonicproject.com/ 生成的属性具有支持变量,以及一些支持INotifyPropertyChanging和INotifyPropertyChanged的额外行,但您可以编辑模板以取出这些行。

以下是示例输出和模板:

public partial class Order
{
    public int OrderID { get; set; }
    public string CustomerID { get; set; }
    public int? EmployeeID { get; set; }
    public DateTime? OrderDate { get; set; }
    public DateTime? RequiredDate { get; set; }
    public DateTime? ShippedDate { get; set; }
    public int? ShipVia { get; set; }
    public decimal? Freight { get; set; }
    public string ShipName { get; set; }
    public string ShipAddress { get; set; }
    public string ShipCity { get; set; }
    public string ShipRegion { get; set; }
    public string ShipPostalCode { get; set; }
    public string ShipCountry { get; set; }
}


<#@ template language="C#" debug="False" hostspecific="True"  #>
<#@ output extension=".cs" #>
<#@ include file="SQLServer.ttinclude" #>
<#
    var tables = LoadTables();
#>
using System;
using System.ComponentModel;
using System.Linq;

namespace <#=Namespace#>
{


<#  foreach(Table tbl in tables){#>    

    /// <summary>
    /// A class which represents the <#=tbl.Name#> table in the <#=DatabaseName#> Database.
    /// This class is queryable through <#=DatabaseName#>DB.<#=tbl.ClassName#> 
    /// </summary>

    public partial class <#=tbl.ClassName#>
    {
        #region Properties

<#      foreach(var col in tbl.Columns){
            if (tbl.ClassName == col.CleanName)
            {
                col.CleanName += "X";
            }
#>
        public <#=col.SysType#><#=CheckNullable(col)#> <#=col.CleanName#> { get; set; }
<#      }#>

        #endregion

    }

<#}#>
}

答案 3 :(得分:0)

github上的

St4bby。开源。 T4。非常容易阅读和操作。

相关问题