Asp.Net Core Api架构设计(一)之T4模板构建

一、总体架构

在这里插入图片描述

1、项目创建

在这里插入图片描述

2、T4模板

T4(Text Template Transformation Toolkit)是微软官方在Visual Studio 2008中开始使用的代码生成引擎。在Visual Studio中,"T4文本模板"是由一些文本块和控制逻辑组成的混合模板,它可以生成文本文件。在Visual C#或Visual Basic中,控制逻辑编写为程序代码的片段。生成的文件可以是任何类型的文本,例如网页、资源文件或任何语言的程序源代码。现在的VS中只要与代码生成相关的场景基本上都能找T4的身影,比如MVC的视图模板,Entity Framework的DataContext模板等等。

2.1、模板的两种类型

2.1.1、设计时模板

在Visual Studio中执行设计时T4文本模板,以便定义应用程序的部分源代码和其他资源。
通常,您可以使用读取单个输入文件或数据库中的数据的多个模板,并生成一些.cs、.vb或其他源文件。每个模板都生成一个文件。在Visual Studio或MSBuild内执行它们。
若要创建设计时模板,请向您的项目中添加“文本模板”文件。另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFileGenerator”。

2.1.2、运行时模板

可在应用程序中执行运行时T4文本模板(“预处理过的”模板)以便生成文本字符串(通常作为其输出的一部分)。
若要创建运行时模板,请向您的项目中添加“已预处理的文本模板”文件。另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFilePreprocessor”

2.2、文本模板的组成

2.2.1、T4模板指令

<#@ template {language=“C#”} {debug=“false”} {hostspecific=“false”} {compilerOptions=“options”} {culture=“code”} {inherits=“Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation”} #>

  • 模板指令中所有特性均为可选的。
  • language:输出语言,有效值C#、VB,默认为C#。
  • debug:是否启用测试,有效值true、false,默认值为false。特别说明下这个调试真的不咋地,很容易让VS崩溃,很鸡肋的功能。
  • hostspecific:有效值true、false,默认为false。如果将此特性的值设置为true,则会将名为Host的属性添加到由文本模板生成的类中。该属性是对转换引擎的宿主的引用,并声明为:Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost。
  • inherits:可以指定模板的程序代码可以继承自另一个类,这个类也可以从文本模板生成。目前没有使用过,基本上可以忽略。
  • compilerOptions:有效值为任何有效的编译器选项。基本上可以忽略

2.2.2、T4参数指令

<#@ parameter type=“Full.TypeName” name=“ParameterName” #>
顾名思义,就是用来传参的,应该是用在运行时模板的(预处理模板)。

2.2.3、T4输出指令

<#@ output extension=“.txt” {encoding=“utf-8”} #>
比较重要的指令,用于设置输出文件的后缀名和文件编码

  • extension:输出文件扩展名,默认为“.cs”
  • encoding:文件编码,默认为utf-8(这里不能确定,我测试是utf-8)。

2.2.4、T4 程序集指令

<#@ assembly name=“[assembly strong name|assembly file name]” #>

  • 程序集指令相当于VS里面我们添加程序集引用的功能,该指令只有一个参数name,用以指定程序集名称,如果程序集已经在GAC里面注册,那么只需要写上程序集名称即可,如<#@
    assembly name=“System.Data.dll” #>,否则需要指定程序集的物理路径。
  • T4模板的程序集引用是完全独立的,也就是说我们在项目中引用了一些程序集,然后项目中添加了一个T4模板,T4模板所需要的所有程序集引用必须明确的在模板中使用程序集执行引用才可以。
  • T4模板自动加载以下程序集Microsoft.VisualStudio.TextTemplating.1*.dll、System.dll、WindowBase.dll,如果用到了其它的程序集需要显示的使用程序集添加引用才可以。
  • 可以使用 ( v a r i a b l e N a m e ) 语法引用 V i s u a l S t u d i o 或 M S B u i l d 变量(如 (variableName)语法引用Visual Studio或MSBuild变量(如 (variableName)语法引用VisualStudioMSBuild变量(如(SolutionDir)),以及使用%VariableName%来引用环境变量。介绍几个常用的$(variableName)变量:
$(SolutionDir):当前项目所在解决方案目录
$(ProjectDir):当前项目所在目录
$(TargetPath):当前项目编译输出文件绝对路径
$(TargetDir):当前项目编译输出目录,即web项目的Bin目录,控制台、
类库项目bin目录下的debug或release(取决于当前的编译模式)
举个例子:比如我们在D盘根目录建立了一个控制台项目TestConsole,
解决方案目录D:\LzrabbitRabbit,项目目录为D:\LzrabbitRabbit\TestConsole,那么此时在Debug编译模式下
$(SolutionDir)的值为D:\LzrabbitRabbit。
$(ProjectDir)的值为D:\LzrabbitRabbit\TestConsole。
$(TargetPath)的值为D:\LzrabbitRabbit\TestConsole\bin\Debug\TestConsole.exe。
$(TargetDir)的值为D:\LzrabbitRabbit\TestConsole\bin\Debug。

2.3、T4导入指令

<#@ import namespace=“System.Linq” #>
在Visual Studio T4文本模板的代码块中,import指令允许您在不提供完全限定名称的情况下引用另一个命名空间中的元素。它等效于C#的using或visual Basic中的imports。默认已经导入了System命名空间的引用。

2.4、T4包含指令

<#@ include file=“filePath” #>

  • filePath可以是绝对的或相对于当前的模板文件。
  • filePath可以包含用"%“分割的环境变量,例如:<#@ include
    file=”%HOMEPATH%\MyIncludeFile.t4" #>
  • 所包含的文件的名称不必使用扩展名".tt"。可能需要针对包含的文件使用其他扩展名,例如:“.t4”。这是因为,在您将.tt文件添加到项目中时,Visual
    Studio会自动将其“自定义工具”属性设置为TextTemplatingFileGenerator。您通常不希望单独转换包含的文件。
  • 在处理时,被包含内容就像是包含文本模板的组成部分一样。不过,即使include指令后为普通文本块和标准控制块,也可以包括含有类功能块<#+…#>的文件。
  • 包含指令可以提高代码复用率,比如我们可以将一些常用的程序集、命名空间引用放到一个文件里,使用时仅需要引用下即可,省去了每次都要重新引用一遍的烦恼,如我们建立Reference.ttinclude文件,里面包含了我们平时常用的程序集。
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>

使用时只需要使用包含指令引用下即可
<#@ include file=“$(ProjectDir)Reference.ttinclude” #>。

2.5、文本块

文本块直接向输出文件插入文本。文本块没有特殊格式。例如:下面的文本模板将生成一个单词“Hello World”
<#@ output extension=“.txt” #>
Hello World!

2.6、 控制块

控制块是用于转换模板的程序代码节。默认语言是C#,但若要使用Visual Basic,可以在文件开头编写以下指令:
<#@ template language=“VB” #>
用于编写控制块代码的语言与生成的文本的语言无关。

2.6.1、标准控制块

标准控制块是生成输出文件部件的程序代码节。
在模板文件中,可以混合使用任意数量的文本块和标准控制块。但是,不能再控制块中嵌套控制块。每个标准控制块都以<#…#>符合分割。
例如,如果使用下面的控制块和文本,则输出文件包含行“0,1,2,3,4 Hello!”:

<#
   for(int i=0;i<4;i++)
   {
      Write(i+",");
   }
    Write("4");
 #>Hello !
您可以交错文本和代码,而不必使用显示Write()语句。以下示例输出"Hello!"四次:
<#
   for(int i=0;i<4;i++)
   {
#>
Hello!
<# 
  }
#>

2.6.2、表达式控制块

表达式控制块计算表达式并将其转换为字符串。该字符串将插入到输出文件中。
表达式控制块以<#=…#>符合分割。
例如,如果使用下面的控制块,则输出文件包含“5”:
<#= 2+3 #>
请注意:开始符号有三个字符"<#="。
表达式可以包含作用域中的任何变量。例如:下面的块输出数字行:

<#
   for(int i=0;i<4;i++)
   {
 #>
 This is hello number <#= i+1 #>:Hello!
 <#
   }
  #>

输出:
This is hello number 1:Hello!
This is hello number 2:Hello!
This is hello number 3:Hello!
This is hello number 4:Hello!

2.6.3、类功能控制块

类功能控制块定义属性、方法或不应包含在主转换中的所有其他代码。类功能块常用于编写帮助器函数。通常,类功能块位于单独的文件中,这样它们可以包含在多个文本模板中。
类功能控制块以<#+…#>符号分割,可以简单的认为<#+…#>定义的内容为我们的类文件。

3、T4模板实战

在这里插入图片描述

3.1、Model.ttinclude

Model.ttinclude 是实体模板引擎,主要是生成XX.cs文件

<#@ assembly name="System.Core"#>
//EnvDTE是一个程序集包装的COM库,其中包含Visual Studio核心自动化的对象和成员。
<#@ assembly name="EnvDTE"#>
<#@ import namespace="System.Collections.Generic"#>
<#@ import namespace="System.IO"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
<#+
class Manager
{
    public struct Block {
        public int Start, Length;
		public String Name,OutputPath;
    }

    public List<Block> blocks = new List<Block>();
    public Block currentBlock;
    public Block footerBlock = new Block();
    public Block headerBlock = new Block();
    public ITextTemplatingEngineHost host;
    public ManagementStrategy strategy;
    public StringBuilder template;
    public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
        this.host = host;
        this.template = template;
        strategy = ManagementStrategy.Create(host);
    }
    public void StartBlock(String name,String outputPath) {
        currentBlock = new Block { Name = name, Start = template.Length ,OutputPath=outputPath};
    }

    public void StartFooter() {
        footerBlock.Start = template.Length;
    }

    public void EndFooter() {
        footerBlock.Length = template.Length - footerBlock.Start;
    }

    public void StartHeader() {
        headerBlock.Start = template.Length;
    }

    public void EndHeader() {
        headerBlock.Length = template.Length - headerBlock.Start;
    }    

    public void EndBlock() {
        currentBlock.Length = template.Length - currentBlock.Start;
        blocks.Add(currentBlock);
    }
    public void Process(bool split) {
        String header = template.ToString(headerBlock.Start, headerBlock.Length);
        String footer = template.ToString(footerBlock.Start, footerBlock.Length);
        blocks.Reverse();
        foreach(Block block in blocks) {
            String fileName = Path.Combine(block.OutputPath, block.Name);
            if (split) {
                String content = header + template.ToString(block.Start, block.Length) + footer;
                strategy.CreateFile(fileName, content);
                template.Remove(block.Start, block.Length);
            } else {
                strategy.DeleteFile(fileName);
            }
        }
    }
}
class ManagementStrategy
{
    internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
        return (host is IServiceProvider) ? new VSManagementStrategy(host) : 
        new ManagementStrategy(host);
    }
    internal ManagementStrategy(ITextTemplatingEngineHost host) { }
    internal virtual void CreateFile(String fileName, String content) {
        File.WriteAllText(fileName, content);
    }

    internal virtual void DeleteFile(String fileName) {
        if (File.Exists(fileName))
            File.Delete(fileName);
    }
}

class VSManagementStrategy : ManagementStrategy
{
    private EnvDTE.ProjectItem templateProjectItem;

    internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
        IServiceProvider hostServiceProvider = (IServiceProvider)host;
        if (hostServiceProvider == null)
            throw new ArgumentNullException("Could not obtain hostServiceProvider");

        EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
        if (dte == null)
            throw new ArgumentNullException("Could not obtain DTE from host");

        templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
    }
    internal override void CreateFile(String fileName, String content) {
        base.CreateFile(fileName, content);
    }
    internal override void DeleteFile(String fileName) {
        ((EventHandler)delegate { FindAndDeleteFile(fileName); }).
        BeginInvoke(null, null, null, null);
    }
    private void FindAndDeleteFile(String fileName) {
        foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
            if (projectItem.get_FileNames(0) == fileName) {
                projectItem.Delete();
                return;
            }
        }
    }
}#>

3.2、DbHelper.ttinclude

DbHelper.ttinclude 是模板引擎,主要是连接数据库生成实体类。

<#+
	public class config
	{
        public static readonly string ConnectionString = "server=.;uid=sa;pwd=123456;database=BlogDB";
        public static readonly string DbDatabase = "";
        public static readonly string TableName = "";
	}
#>
<#+ 
    public class DbHelper
    {
        #region GetDbTables
		 public static List<string> GetDbTablesNew(string connectionString, string database,string tables = null)
        { 
			 if (!string.IsNullOrEmpty(tables))
            {
                tables = string.Format(" and obj.name in ('{0}')", tables.Replace(",", "','"));
            }
            string sql = string.Format(@"SELECT
                obj.name tablename
                from {0}.sys.objects obj 
                inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
                INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
                left join {0}.sys.extended_properties g ON (obj.object_id = g.major_id AND g.minor_id = 0 AND g.name= 'MS_Description')
                where type='U' {1} 
                order by obj.name", database,tables);
            DataTable dt = GetDataTable(connectionString, sql);
            return dt.Rows.Cast<DataRow>().Select(row =>row.Field<string>("tablename")).ToList();
        }

        public static List<DbTable> GetDbTables(string connectionString, string database, string tables = null)
        {
            if (!string.IsNullOrEmpty(tables))
            {
                tables = string.Format(" and obj.name in ('{0}')", tables.Replace(",", "','"));
            }
            #region SQL
            string sql = string.Format(@"SELECT
									obj.name tablename,
									schem.name schemname,
									idx.rows,
									CAST
									(
										CASE 
											WHEN (SELECT COUNT(1) FROM sys.indexes WHERE object_id= obj.OBJECT_ID AND is_primary_key=1) >=1 THEN 1
											ELSE 0
										END 
									AS BIT) HasPrimaryKey                                         
									from {0}.sys.objects obj 
									inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
									INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
									where type='U' {1}
									order by obj.name", database, tables);
            #endregion
            DataTable dt = GetDataTable(connectionString, sql);
            return dt.Rows.Cast<DataRow>().Select(row => new DbTable
            {
                TableName = row.Field<string>("tablename"),
                SchemaName = row.Field<string>("schemname"),
                Rows = row.Field<int>("rows"),
                HasPrimaryKey = row.Field<bool>("HasPrimaryKey")
            }).ToList();
        }
        #endregion

        #region GetDbColumns
        public static List<DbColumn> GetDbColumns(string connectionString, string database, string tableName, string schema = "dbo")
        {
            #region SQL
            string sql = string.Format(@"
                                    WITH indexCTE AS
                                    (
	                                    SELECT 
                                        ic.column_id,
                                        ic.index_column_id,
                                        ic.object_id    
                                        FROM {0}.sys.indexes idx
                                        INNER JOIN {0}.sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id
                                        WHERE  idx.object_id =OBJECT_ID(@tableName) AND idx.is_primary_key=1
                                    )
                                    select
									colm.column_id ColumnID,
                                    CAST(CASE WHEN indexCTE.column_id IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey,
                                    colm.name ColumnName,
                                    systype.name ColumnType,
                                    colm.is_identity IsIdentity,
                                    colm.is_nullable IsNullable,
                                    cast(colm.max_length as int) ByteLength,
                                    (
                                        case 
                                            when systype.name='nvarchar' and colm.max_length>0 then colm.max_length/2 
                                            when systype.name='nchar' and colm.max_length>0 then colm.max_length/2
                                            when systype.name='ntext' and colm.max_length>0 then colm.max_length/2 
                                            else colm.max_length
                                        end
                                    ) CharLength,
                                    cast(colm.precision as int) Precision,
                                    cast(colm.scale as int) Scale,
                                    prop.value Remark
                                    from {0}.sys.columns colm
                                    inner join {0}.sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id
                                    left join {0}.sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id
                                    LEFT JOIN indexCTE ON colm.column_id=indexCTE.column_id AND colm.object_id=indexCTE.object_id                                        
                                    where colm.object_id=OBJECT_ID(@tableName)
                                    order by colm.column_id", database);
            #endregion
            SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, 100) { Value = string.Format("{0}.{1}.{2}", database, schema, tableName) };
            DataTable dt = GetDataTable(connectionString, sql, param);
            return dt.Rows.Cast<DataRow>().Select(row => new DbColumn()
            {
                ColumnID = row.Field<int>("ColumnID"),
                IsPrimaryKey = row.Field<bool>("IsPrimaryKey"),
                ColumnName = row.Field<string>("ColumnName"),
                ColumnType = row.Field<string>("ColumnType"),
                IsIdentity = row.Field<bool>("IsIdentity"),
                IsNullable = row.Field<bool>("IsNullable"),
                ByteLength = row.Field<int>("ByteLength"),
                CharLength = row.Field<int>("CharLength"),
				Precision=row.Field<int>("Precision"),
                Scale = row.Field<int>("Scale"),
                Remark = row["Remark"].ToString()
            }).ToList();
        }
        #endregion
        #region GetDataTable
        public static DataTable GetDataTable(string connectionString, string commandText, params SqlParameter[] parms)
        {
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                SqlCommand command = connection.CreateCommand();
                command.CommandText = commandText;
                command.Parameters.AddRange(parms);
                SqlDataAdapter adapter = new SqlDataAdapter(command);
                DataTable dt = new DataTable();
                adapter.Fill(dt);
                return dt;
            }
        }

        #endregion

	    #region GetPrimaryKey
        public static string GetPrimaryKey(List<DbColumn> dbColumns)
        {
            string primaryKey = string.Empty;
            if (dbColumns!=null&&dbColumns.Count>0)
            {
                foreach (var item in dbColumns)
                {
                    if (item.IsPrimaryKey==true)
                    {
                        primaryKey = item.ColumnName;
                    }
                }
            }
            return primaryKey;
        }
        #endregion
    }

    #region DbTable
    public sealed class DbTable
    {
        public string TableName { get; set; }
        public string SchemaName { get; set; }
        public int Rows { get; set; }
        public bool HasPrimaryKey { get; set; }
    }
    #endregion

    #region DbColumn   
    public sealed class DbColumn
    {        
        public int ColumnID { get; set; }       
        public bool IsPrimaryKey { get; set; }     
        public string ColumnName { get; set; }       
        public string ColumnType { get; set; }      
        public string CSharpType
        {
            get
            {
                return SqlServerDbTypeMap.MapCsharpType(ColumnType);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Type CommonType
        {
            get
            {
                return SqlServerDbTypeMap.MapCommonType(ColumnType);
            }
        }
        public int ByteLength { get; set; }
        public int CharLength { get; set; }
		public int Precision{get;set;}
        public int Scale { get; set; }
        public bool IsIdentity { get; set; }
        public bool IsNullable { get; set; }
        public string Remark { get; set; }
    }
    #endregion

    #region SqlServerDbTypeMap

    public class SqlServerDbTypeMap
    {
        public static string MapCsharpType(string dbtype)
        {
            if (string.IsNullOrEmpty(dbtype)) return dbtype;
            dbtype = dbtype.ToLower();
            string csharpType = "object";
            switch (dbtype)
            {
                case "bigint": csharpType = "long"; break;
                case "binary": csharpType = "byte[]"; break;
                case "bit": csharpType = "bool"; break;
                case "char": csharpType = "string"; break;
                case "date": csharpType = "DateTime"; break;
                case "datetime": csharpType = "DateTime"; break;
                case "datetime2": csharpType = "DateTime"; break;
                case "datetimeoffset": csharpType = "DateTimeOffset"; break;
                case "decimal": csharpType = "decimal"; break;
                case "float": csharpType = "double"; break;
                case "image": csharpType = "byte[]"; break;
                case "int": csharpType = "int"; break;
                case "money": csharpType = "decimal"; break;
                case "nchar": csharpType = "string"; break;
                case "ntext": csharpType = "string"; break;
                case "numeric": csharpType = "decimal"; break;
                case "nvarchar": csharpType = "string"; break;
                case "real": csharpType = "Single"; break;
                case "smalldatetime": csharpType = "DateTime"; break;
                case "smallint": csharpType = "short"; break;
                case "smallmoney": csharpType = "decimal"; break;
                case "sql_variant": csharpType = "object"; break;
                case "sysname": csharpType = "object"; break;
                case "text": csharpType = "string"; break;
                case "time": csharpType = "TimeSpan"; break;
                case "timestamp": csharpType = "byte[]"; break;
                case "tinyint": csharpType = "byte"; break;
                case "uniqueidentifier": csharpType = "Guid"; break;
                case "varbinary": csharpType = "byte[]"; break;
                case "varchar": csharpType = "string"; break;
                case "xml": csharpType = "string"; break;
                default: csharpType = "object"; break;
            }
            return csharpType;
        }

        public static Type MapCommonType(string dbtype)
        {
            if (string.IsNullOrEmpty(dbtype)) return Type.Missing.GetType();
            dbtype = dbtype.ToLower();
            Type commonType = typeof(object);
            switch (dbtype)
            {
                case "bigint": commonType = typeof(long); break;
                case "binary": commonType = typeof(byte[]); break;
                case "bit": commonType = typeof(bool); break;
                case "char": commonType = typeof(string); break;
                case "date": commonType = typeof(DateTime); break;
                case "datetime": commonType = typeof(DateTime); break;
                case "datetime2": commonType = typeof(DateTime); break;
                case "datetimeoffset": commonType = typeof(DateTimeOffset); break;
                case "decimal": commonType = typeof(decimal); break;
                case "float": commonType = typeof(double); break;
                case "image": commonType = typeof(byte[]); break;
                case "int": commonType = typeof(int); break;
                case "money": commonType = typeof(decimal); break;
                case "nchar": commonType = typeof(string); break;
                case "ntext": commonType = typeof(string); break;
                case "numeric": commonType = typeof(decimal); break;
                case "nvarchar": commonType = typeof(string); break;
                case "real": commonType = typeof(Single); break;
                case "smalldatetime": commonType = typeof(DateTime); break;
                case "smallint": commonType = typeof(short); break;
                case "smallmoney": commonType = typeof(decimal); break;
                case "sql_variant": commonType = typeof(object); break;
                case "sysname": commonType = typeof(object); break;
                case "text": commonType = typeof(string); break;
                case "time": commonType = typeof(TimeSpan); break;
                case "timestamp": commonType = typeof(byte[]); break;
                case "tinyint": commonType = typeof(byte); break;
                case "uniqueidentifier": commonType = typeof(Guid); break;
                case "varbinary": commonType = typeof(byte[]); break;
                case "varchar": commonType = typeof(string); break;
                case "xml": commonType = typeof(string); break;
                default: commonType = typeof(object); break;
            }
            return commonType;
        }
    }
    #endregion
 #>

3.3、BlogStudy.FrameWork.Model.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension="/" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)Model.ttinclude"	#>
<# var manager = new Manager(Host, GenerationEnvironment, true); #>
<# 
	var OutputPath1 =Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Host.TemplateFile+"..")+"..")+"..");
	OutputPath1=Path.Combine(OutputPath1,"BlogStudy.Model","Models_New");
	if (!Directory.Exists(OutputPath1))
	{
	    Directory.CreateDirectory(OutputPath1);
	}
#>

<# foreach (var item in DbHelper.GetDbTablesNew(config.ConnectionString, config.DbDatabase,config.TableName))
   {
		var tableName=item.ToString();
		manager.StartBlock(tableName+".cs",OutputPath1);//文件名
#>

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlogStudy.Model.Models
{
	 ///<summary>
	 ///<#=tableName#>
	 ///</summary>
	 [Table("<#=tableName#>")]	
	 public class <#=tableName#>
	 {
	 <# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, tableName)){#>

		/// <summary>
        /// <#= column.Remark == "" ? column.ColumnName : column.Remark.Replace("\r\n"," ") #>
        /// </summary>
		<# 
		 if(column.IsPrimaryKey) 
		{#>[Key]
		<#}#><# if(!column.IsNullable) {#>[Required]
		<# }#>public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName#> { get; set; }
	 <#
	 }
	 #> 
	 }
}

<#
   manager.EndBlock(); 
   }
   manager.Process(true);
#>

3.4、BlogStudy.FrameWork.Repository.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)ModelAuto.ttinclude"	#>
<# var manager = new Manager(Host, GenerationEnvironment, true); #>


<# 
	var OutputPath1 =Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Host.TemplateFile+"..")+"..")+"..");
	OutputPath1=Path.Combine(OutputPath1,"BlogStudy.Core.Repository","Repositories_New");
	if (!Directory.Exists(OutputPath1))
	{
	    Directory.CreateDirectory(OutputPath1);
	}
#>


//--------------------------------------------------------------------
//     此代码由T4模板自动生成
//	   生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
<# 
	var tableName=config.TableName;
 #>
<# 
if(tableName!=""){
#>  

using BlogStudy.Repository.Base;
using BlogStudy.Model.Models;
using BlogStudy.IRepository;
using BlogStudy.IRepository.UnitOfWork;
namespace BlogStudy.Repository
{	
	/// <summary>
	/// <#=tableName#>Repository
	/// </summary>	
	public class <#=tableName#>Repository : BaseRepository<<#=tableName#>>, I<#=tableName#>Repository
    {
		
    }
}

<# 
} else{ 
#>

<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
#>

<# 
foreach(System.Data.DataRow row in schema.Rows) 
{  
	manager.StartBlock(row["TABLE_NAME"].ToString()+"Repository"+".cs",OutputPath1);
	#>
//----------<#=row["TABLE_NAME"].ToString()#>开始----------   

using BlogStudy.Core.Repository.Base;
using BlogStudy.Core.Model.Models;
using BlogStudy.Core.IRepository;
using BlogStudy.Core.IRepository.UnitOfWork;
namespace BlogStudy.Repository
{	
	/// <summary>
	/// <#=row["TABLE_NAME"].ToString()#>Repository
	/// </summary>	
	public class <#=row["TABLE_NAME"].ToString()#>Repository : BaseRepository<<#=row["TABLE_NAME"].ToString()#>>, I<#=row["TABLE_NAME"].ToString() #>Repository
    {
		public <#=row["TABLE_NAME"].ToString()#>Repository(IUnitOfWork unitOfWork) : base(unitOfWork)
        {
        }
       
    }
}

//----------<#=row["TABLE_NAME"].ToString()#>结束----------
<# 
	manager.EndBlock(); 
	} 

	{  
	manager.StartBlock("BaseRepository.cs",OutputPath1);//文件名
	#>
    
//----------开始----------
	
using BlogStudy.Core.Repository.Base;
using BlogStudy.Core.Model.Models;
using BlogStudy.Core.IRepository;
using BlogStudy.Core.IRepository.UnitOfWork;
namespace BlogStudy.Repository
{	
	/// <summary>
	/// IBaseRepository
	/// </summary>	
	 public  class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class, new()
    {
       
    }
}

//----------结束----------
<# 
	manager.EndBlock(); 
	} 
	manager.Process(true);
}
#> 


3.5、BlogStudy.FrameWork.IRepository.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)Model.ttinclude"	#>
<# var manager = new Manager(Host, GenerationEnvironment, true); #>


<# 
	var OutputPath1 =Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Host.TemplateFile+"..")+"..")+"..");
	OutputPath1=Path.Combine(OutputPath1,"BlogStudy.IRepository","IRepositories_New");
	if (!Directory.Exists(OutputPath1))
	{
	    Directory.CreateDirectory(OutputPath1);
	}
#>


//--------------------------------------------------------------------
//     此代码由T4模板自动生成
//	   生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
<# 
	var tableName=config.TableName;
#>
<# 
if(tableName!=""){
#>  
using BlogStudy.IRepository.Base;
using BlogStudy.Model.Models;
namespace BlogStudy.IRepository
{	
	/// <summary>
	/// I<#=tableName#>Repository
	/// </summary>	
	public interface I<#=tableName#>Repository : IBaseRepository<<#=tableName#>>
    {
      
    }
}

<# 
} else{ 
#>
<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
#>

<# 
foreach(System.Data.DataRow row in schema.Rows) 
{  
	manager.StartBlock("I"+row["TABLE_NAME"].ToString()+"Repository"+".cs",OutputPath1);//文件名
	#>
//----------<#=row["TABLE_NAME"].ToString()#>开始----------
    
using BlogStudy.IRepository.Base;
using BlogStudy.Model.Models;
namespace BlogStudy.IRepository
{	
	/// <summary>
	/// I<#=row["TABLE_NAME"].ToString()#>Repository
	/// </summary>	
	public interface I<#=row["TABLE_NAME"].ToString()#>Repository : IBaseRepository<<#=row["TABLE_NAME"].ToString()#>>//类名
    {

       
    }
}

//----------<#=row["TABLE_NAME"].ToString()#>结束----------
<# 
	manager.EndBlock(); 
	} 

	{  
	manager.StartBlock("IBaseRepository.cs",OutputPath1);//文件名
	#>
    
//----------开始----------
	
using BlogStudy.IRepository.Base;
using BlogStudy.Model.Models;
namespace BlogStudy.IRepository
{	
	/// <summary>
	/// IBaseRepository
	/// </summary>	
	public interface IBaseRepository<TEntity> where TEntity : class
    {
       
    }
}
//----------结束----------
<# 
	manager.EndBlock(); 
	} 
	manager.Process(true);
}
#> 

3.6、BlogStudy.FrameWork.Service.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)Model.ttinclude"	#>
<# var manager = new Manager(Host, GenerationEnvironment, true); #>


<# 
	var OutputPath1 =Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Host.TemplateFile+"..")+"..")+"..");
	OutputPath1=Path.Combine(OutputPath1,"BlogStudy.Services","Services_New");
	if (!Directory.Exists(OutputPath1))
	{
	    Directory.CreateDirectory(OutputPath1);
	}
#>

//--------------------------------------------------------------------
//     此代码由T4模板自动生成
//	   生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
<# 
	var tableName=config.TableName;
 #>
<# 
if(tableName!=""){
#>  

using System;
using System.Threading.Tasks;
using BlogStudy.Common;
using BlogStudy.IRepository;
using BlogStudy.IRepository.UnitOfWork;
using BlogStudy.IServices;
using BlogStudy.Model.Models;
using BlogStudy.Services.Base;
namespace BlogStudy.Services
{	
	/// <summary>
	/// <#=tableName#>Services
	/// </summary>	
	public class <#=tableName#>Services : BaseServices<<#=tableName#>>, I<#=tableName#>Services
    {
	
        I<#=tableName#>Repository dal;
        public <#=tableName#>Services(I<#=tableName#>Repository dal)
        {
            this.dal = dal;
            base.baseDal = dal;
        }
       
    }
}

<# 
} else{ 
#>

<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
#>

<# 
foreach(System.Data.DataRow row in schema.Rows) 
{  
	manager.StartBlock(row["TABLE_NAME"].ToString()+"Services"+".cs",OutputPath1);
	#>
//----------<#=row["TABLE_NAME"].ToString()#>开始----------
    
using System;
using System.Threading.Tasks;
using BlogStudy.Common;
using BlogStudy.IRepository;
using BlogStudy.IRepository.UnitOfWork;
using BlogStudy.IServices;
using BlogStudy.Model.Models;
using BlogStudy.Services.Base;
namespace BlogStudy.Services
{	
	/// <summary>
	/// <#=row["TABLE_NAME"].ToString()#>Services
	/// </summary>	
	public class <#=row["TABLE_NAME"].ToString()#>Services : BaseServices<<#=row["TABLE_NAME"].ToString()#>>, I<#=row["TABLE_NAME"].ToString() #>Services
    {
	
        I<#=row["TABLE_NAME"].ToString() #>Repository dal;
        public <#=row["TABLE_NAME"].ToString() #>Services(I<#=row["TABLE_NAME"].ToString() #>Repository dal)
        {
            this.dal = dal;
            base.baseDal = dal;
        }
       
    }
}

//----------<#=row["TABLE_NAME"].ToString()#>结束----------
<# 
	manager.EndBlock(); 
	} 
	{  
	manager.StartBlock("BaseServices.cs",OutputPath1);//文件名
	#>
    
//----------开始----------
	

using System;
using System.Threading.Tasks;
using BlogStudy.Common;
using BlogStudy.IRepository;
using BlogStudy.IRepository.UnitOfWork;
using BlogStudy.IServices;
using BlogStudy.Model.Models;
using BlogStudy.Services.BASE;
namespace BlogStudy.Services
{	
	/// <summary>
	/// IBaseRepository
	/// </summary>	
	public class BaseServices<TEntity> : IBaseServices<TEntity> where TEntity : class, new()
    {
		public IBaseRepository<TEntity> baseDal;
       
    }
}

//----------结束----------
<# 
	manager.EndBlock(); 
	} 
	manager.Process(true);
}
#> 

3.7、BlogStudy.FrameWork.IService.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)Model.ttinclude"	#>
<# var manager = new Manager(Host, GenerationEnvironment, true); #>

<# 
	var OutputPath1 =Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Host.TemplateFile+"..")+"..")+"..");
	OutputPath1=Path.Combine(OutputPath1,"BlogStudy.IServices","IServices_New");
	if (!Directory.Exists(OutputPath1))
	{
	    Directory.CreateDirectory(OutputPath1);
	}
#>



//--------------------------------------------------------------------
//     此代码由T4模板自动生成
//	   生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
<# 
	var tableName=config.TableName;
#>
<# 
if(tableName!=""){
#>  


using BlogStudy.IServices.Base;
using BlogStudy.Model.Models;

namespace BlogStudy.IServices
{	
	/// <summary>
	/// I<#=tableName#>Services
	/// </summary>	
	public interface I<#=tableName#>Services :IBaseServices<<#=tableName#>>
    {    
    }
}

<# 
} else{ 
#>

<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
#>

<# 
foreach(System.Data.DataRow row in schema.Rows) 
{  
	manager.StartBlock("I"+row["TABLE_NAME"].ToString()+"Services"+".cs",OutputPath1);
	#>
//----------<#=row["TABLE_NAME"].ToString()#>开始----------
    

using BlogStudy.IServices.Base;
using BlogStudy.Model.Models;

namespace BlogStudy.IServices
{	
	/// <summary>
	/// <#=row["TABLE_NAME"].ToString()#>Services
	/// </summary>	
    public interface I<#=row["TABLE_NAME"].ToString()#>Services :IBaseServices<<#=row["TABLE_NAME"].ToString()#>>
	{

       
    }
}

//----------<#=row["TABLE_NAME"].ToString()#>结束----------
<# 
	manager.EndBlock(); 
	} 

	{  
	manager.StartBlock("IBaseServices.cs",OutputPath1);//文件名
	#>
    
//----------开始----------
	
using BlogStudy.IServices.Base;
using BlogStudy.Model.Models;

namespace BlogStudy.IServices
{	
	/// <summary>
	/// IBaseRepository
	/// </summary>	
	public interface IBaseServices<TEntity> where TEntity : class
    {

       
    }
}

//----------结束----------
<# 
	manager.EndBlock(); 
	} 
	manager.Process(true);
}
#> 


  • 0
    点赞
  • 3
    收藏
  • 打赏
    打赏
  • 0
    评论
课程通过实际项目融入常用开发技术架构,讲授风格独特,提供详细上课日志及答疑,赠送配套的项目架构源码注释详细清晰且表达通俗,均能直接在实际项目中应用,正真的物超所值,价格实惠 任务作业: 综合运用《C#/.Net企业级系统架构设计实战精讲教程》课程所学知识技能设计一个学生成绩管理系统的架构。要求: 1.系统基于MVC的三层架构,各层单独建不同的解决方案文件夹。 2.采用Model First开发方式,设计架构时只需要设计学生表(TbStudent)和课程表(TbCourse)。学生表必须有的字段是ID、stuName、age;课程表必须有的字段是ID、courseName、content。 3.数据访问层采用Entity Framework或NHibernate来实现,必须封装对上述表的增删改查方法。 4.必须依赖接口编程,也就是必须要有数据访问层的接口层、业务逻辑层的接口层等接口层。层层之间必须减少依赖,可以通过简单工厂或抽象工厂。 5.至少采用简单工厂、抽象工厂、Spring.Net等技术中的2种来减少层与层之间的依赖等。 6.封装出DbSession类,让它拥有所有Dal层实例和SaveChanges方法。 7.设计出数据访问层及业务逻辑层主要类的T4模板,以便实体增加时自动生成相应的类。 8.表现层要设计相关的控制器和视图来验证设计的系统架构代码的正确性,必须含有验证增删改查的方法。 9.开发平台一定要是Visual Studio平台,采用C#开发语言,数据库为SQL Server。 10.提交整个系统架构的源文件及生成的数据库文件。 (注意: 作业需写在CSDN博客中,请把作业链接贴在评论区,老师会定期逐个批改~~)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:猿与汪的秘密 设计师:我叫白小胖 返回首页
评论

打赏作者

sufengmarket

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值