code first使用t4模板
http://stackoverflow.com/questions/23347093/dbcontext-generator-t4-templates-with-code-first
dbfist使用t4模板edmx文件
codefirst没有edmx文件,只有dbcontext类文件,稍微有点不一样。
第一步、添加EF6.Utility.CS.ttinclude文件
路径为C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes
第二步、修改此文件
在include文件中有三个方法很重要
public IEnumerable<GlobalItem> CreateEdmItemCollection(string sourcePath) public XElement LoadRootElement(string sourcePath) private void ProcessErrors(IEnumerable<EdmSchemaError> errors, string sourceFilePath)
最重要的是LoadRootElement方法,读取xml文件,因为codefirst没有edmx,也没有这样的xml文件,我们就准备一个内存流来存取dbcontext信息。
在里面添加两个方法
public IEnumerable<GlobalItem> CreateEdmItemCollection(DbContext dbContext) { ArgumentNotNull(dbContext, "dbContext"); var schemaElement = LoadRootElement(dbContext); if (schemaElement != null) { using (var reader = schemaElement.CreateReader()) { IList<EdmSchemaError> errors; var itemCollection = EdmItemCollection.Create(new[] { reader }, null, out errors); ProcessErrors(errors, dbContext.Database.Connection.ConnectionString); return itemCollection ?? new EdmItemCollection(); } } return new EdmItemCollection(); } public XElement LoadRootElement(DbContext dbContext) { ArgumentNotNull(dbContext, "dbContext"); XElement root; using (var stream = new MemoryStream()) { using (var writer = XmlWriter.Create(stream)) { EdmxWriter.WriteEdmx(dbContext, writer); } stream.Position = 0; root = XElement.Load(stream, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); root = root.Elements() .Where(e => e.Name.LocalName == "Runtime") .Elements() .Where(e => e.Name.LocalName == "ConceptualModels") .Elements() .Where(e => e.Name.LocalName == "Schema") .FirstOrDefault() ?? root; } return root; }
然后导入命名空间
<#@ assembly name="System.Data.Entity" #> <#@ import namespace="System.Data.Entity" #> <#@ import namespace="System.Data.Entity.Infrastructure" #>
第三步、修改t4文件
生成多个cs文件:
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ assembly name="$(SolutionDir)Web\bin\Model.dll"#> <#@ include file="EF6.Utility.CS.ttinclude"#><#@ output extension=".txt" encoding="utf-8"#><# //模板准备 const string connectionString = @"Server=(LocalDb)\v11.0;Database=db;Integrated Security=True;MultipleActiveResultSets=True"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); IEnumerable<GlobalItem> itemCollection; using (var dbContext = new Model.CodeFirstContext(connectionString)) { itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(dbContext); if (itemCollection == null) { return string.Empty; } } var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), connectionString)) { return string.Empty; } //WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { fileManager.StartNewFile("I"+entity.Name + "BLL.cs"); #>
Model.dll是包含dbcontext文件的类库。
接下来是自己代码
foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { fileManager.StartNewFile("I"+entity.Name + "BLL.cs"); #> <# BeginNamespace(code); #> <#=codeStringGenerator.UsingDirectives(inHeader: false)#> <#="public interface I"+entity.Name+"BLL:IBaseBLL"#> { } <# EndNamespace(code); #> <# }#>
生成单个cs文件:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IBLL { public partial interface IBLLSession { <# foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { #> I<#=entity.Name#>BLL I<#= entity.Name #>BLL {get;set;} <#}#> } }
下面是模板里的一些方法,不要去改动。
补充:模板里的方法怎么来的。
新建一个ado.net数据文件,连接数据库会得到edmx文件,里面就有,可以copy。
这个是ef6的tt模板,回过头来,我们就是把这个模板头部文件进行修改,读程序集而不是edmx文件。