使用T4模板生成代碼的學習


  之前做項目使用的都是Db First,直接在項目中添加Entity Framework,使用T4模板(T4模板引擎之基礎入門)生成DAL BLL層等(T4模板是一個同事給的,也沒有仔細研究,代碼如下:)

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#

CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);

string inputFile = @"..\\TestProject.Model\\EFData.edmx";

EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
string namespaceName = code.VsNamespaceSuggestion();

EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);

#>
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using DianXin.TianYi.Model;
using DianXin.TianYi.IDAL;

namespace TestProjectDAL
{    
    <#    
    foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
    {       
    #>            
        public partial class <#=entity.Name#>DAL : BaseDAL<<#=entity.Name#>>, I<#=entity.Name#>DAL {}
    <#
    }
    #>
}

現在突然想用一下Code First改變一下(覺得直接在Model上加特性標簽,挺爽的,省去再使用“BuddyClass”做驗證了),但突然發現上面的代碼不能用了,令人感覺有點小郁悶(其實是個人比較懶了),就仔細翻看一下這方面的資料(關於上面代碼可以參考:實體框架實用工具.ttinclude文件)。但覺得網上沒有介紹在CodeFirst中使用T4生成DAL層的文章或者文章有點太老了,里面方法沒有實驗成功,也有點讓人看不懂。經過七拼八揍終於被我整出來了,其中也遇到了幾個小問題,就在這記錄一下。

1.關於錯誤" 正在編譯轉換: 未能找到類型或命名空間名稱“TestProject”(是否缺少 using 指令或程序集引用?) ",是因為直接在T4模板里使用<#@ import namespace="TestProject.Model" #>,才報的這個錯,這里要說明一下,如果添加系統引用是沒有問題。(eg: <#@ important namespace="System.Data.SqlClient" #>),T4測試代碼如下:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="TestProject.Model" #>
<#@ output extension=".cs" #>

解決此問題可以簡單分為3步:

第1步,先引入dll文件

代碼如下:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ assembly name="$(SolutionDir)\TestProject.Model\bin\Debug\TestProject.Model.dll" #>
<#@ output extension=".cs" #>

其中”$(SolutionDir)“是指解決方案目錄,這種稱做VS宏的方式。具體有以下幾個系統VS宏:

$(SolutionDir) 當前項目所在解決方案目錄
$(ProjectDir) 當前項目所在目錄
$(TargetPath) 前項目編譯輸出文件絕對路徑
$(TargetDir) 當前項目編譯輸出目錄,即web項目的Bin目錄,控制台、類庫項目bin目錄下的debug或release目錄(取決於當前的編譯模式)

第2步:在第1步的基礎上添加命名空間就可以了,代碼如下:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ assembly name="$(SolutionDir)\TestProject.Model\bin\Debug\TestProject.Model.dll" #>
<#@ import namespace="TestProject.Model" #>
<#@ output extension=".cs" #>

第3步:就可以直接寫代碼了,我的做法是先獲得TestContext(這個類繼承了DbContext)里的所有屬性,判斷屬性的類型名中包含DbSet的屬性,然后再獲得屬性里的泛型類型數組,就可以獲得類。示例代碼如下:

TestContext:

public partial class TestContext : DbContext
{
    public TestContext() : base("TestDatabase") { }

    public DbSet<Teacher> Teachers { get; set; }
        
    public DbSet<Person> Persons { get; set; }

    public DbSet<Student> Students { get; set; }
}

EntityClassInfo:(通過該類可以獲得TestContext里所有類型為DbSet的類名稱)

public class EntityClassInfo
    {
        public EntityClassInfo()
        {
            List<string> classNameList = new List<string>();
            PropertyInfo[] properties = typeof(TestContext).GetProperties();    // 獲得對象所有屬性
            foreach (var property in properties)
            {
                string propertyType = property.PropertyType.Name;   // 獲得屬性類型名稱
                if (propertyType.Contains("DbSet"))     // 判斷是否為實體集合
                {
                    Type[] genericTypes = property.PropertyType.GenericTypeArguments;   // 獲得泛型類型數組
                    foreach (var type in genericTypes)
                    {
                        classNameList.Add(type.Name);   // 獲得泛型類型名稱 並添加到集合中
                    }
                }
            }
            this.EntitiesList = classNameList;
        }

        public List<string> EntitiesList { get; set; }
    }

T4代碼:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(SolutionDir)\TestProject.Model\bin\Debug\TestProject.Model.dll" #>
<#@ import namespace="TestProjectModel" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
var entity = new EntityClassInfo();
foreach(var item in entity.EntitiesList)
{#>
    <#=item#>
<#}#>

參考資料:解決T4模板的程序集引用出錯(5種方案)

就這樣吧,如有錯誤之處,請大牛們指出,謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM