EF學習筆記——生成自定義實體類
阿新 • • 發佈:2018-11-09
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
使用EF,採用DataBase 模式,實體類都是按照資料庫的定義自動生成,我們似乎無法干預。如果要生成自定義的實體類,該怎麼做呢?
思路是這樣的:
1、我們要自定義生成的實體類,都是分部類(partial),目的是對EF生成的實體類進行擴充;
2、擴充部分,預先寫好在模板裡,自動生成
3、每個實體類,都進行擴充
實施方法:
1、給VS2012安裝兩個外掛:
- Devart T4 Editor:為VS提供智慧提示功能。
- T4 Toolbox:在生成多檔案時很有用。
1)建立T4 Toolbox模板檔案EntityTemplate.tt,作用是生成多個實體類檔案
程式碼如下:
<#+// <copyright file="Entity.tt" company="cqxm">// Copyright © . All Rights Reserved. // </copyright>public class Entity : CSharpTemplate{ private string _className; public Entity(string className) { _className = className; } public override string TransformText () { base.TransformText();#>namespace testEF{ public partial class <#= _className #> : IEntity { public string _ID { get { return Id.ToString(); } } }}<#+ return this.GenerationEnvironment.ToString(); }}#>
2)建立T4模板檔案EntityOutput.tt,呼叫前面寫的EntityTemplate.tt,真正生成各種實體類檔案
<#@ template debug="false" hostspecific="false" language="C#" #><#@ assembly name="System.Core" #><#@ import namespace="System.IO" #><#@ import namespace="System.Linq" #><#@ import namespace="System.Text" #><#@ import namespace="System.Collections.Generic" #><#@ include file="EF.Utility.CS.ttinclude"#><#@ include file="T4Toolbox.tt" #><#@ include file="EntityTemplate.tt" #><# string curPath = Path.GetDirectoryName(Host.TemplateFile); string destPath = Path.Combine(curPath, @"..\Partial");//將各個擴充實體類檔案生成到資料夾Partial下 if(!Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); } const string inputFile = @"..\ShowMe.edmx"; var textTransform = DynamicTextTransformation.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); foreach (var entity in GetItemsToGenerate<EntityType>(itemCollection)) {//每個實體類都要自動生成擴充檔案,是自動哦,參考文章裡介紹的是手動輸入實體類名稱 Entity template = new Entity(entity.Name); string fileName = string.Format(@"{0}\{1}.cs", destPath, entity.Name); template.Output.Encoding = Encoding.UTF8; if(File.Exists(fileName)) { File.Delete(fileName); } template.RenderToFile(fileName); }#><#+/*以下程式碼都是為了獲得EF自動生成的所有實體類名單,抄自 *.edmx\*.Context.tt。沒辦法,誰叫俺看不懂哪些程式碼呢*/public class EdmMetadataLoader{ private readonly IDynamicHost _host; private readonly System.Collections.IList _errors; public EdmMetadataLoader(IDynamicHost host, System.Collections.IList errors) { ArgumentNotNull(host, "host"); ArgumentNotNull(errors, "errors"); _host = host; _errors = errors; } public IEnumerable<GlobalItem> CreateEdmItemCollection(string sourcePath) { ArgumentNotNull(sourcePath, "sourcePath"); if (!ValidateInputPath(sourcePath)) { return new EdmItemCollection(); } var schemaElement = LoadRootElement(_host.ResolvePath(sourcePath)); if (schemaElement != null) { using (var reader = schemaElement.CreateReader()) { IList<EdmSchemaError> errors; var itemCollection = MetadataItemCollectionFactory.CreateEdmItemCollection(new[] { reader }, out errors); ProcessErrors(errors, sourcePath); return itemCollection; } } return new EdmItemCollection(); } public string GetModelNamespace(string sourcePath) { ArgumentNotNull(sourcePath, "sourcePath"); if (!ValidateInputPath(sourcePath)) { return string.Empty; } var model = LoadRootElement(_host.ResolvePath(sourcePath)); if (model == null) { return string.Empty; } var attribute = model.Attribute("Namespace"); return attribute != null ? attribute.Value : ""; } private bool ValidateInputPath(string sourcePath) { if (sourcePath == "$" + "edmxInputFile" + "$") { _errors.Add( new CompilerError(_host.TemplateFile ?? sourcePath, 0, 0, string.Empty, GetResourceString("Template_ReplaceVsItemTemplateToken"))); return false; } return true; } public XElement LoadRootElement(string sourcePath) { ArgumentNotNull(sourcePath, "sourcePath"); var root = XElement.Load(sourcePath, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); return root.Elements() .Where(e => e.Name.LocalName == "Runtime") .Elements() .Where(e => e.Name.LocalName == "ConceptualModels") .Elements() .Where(e => e.Name.LocalName == "Schema") .FirstOrDefault() ?? root; } private void ProcessErrors(IEnumerable<EdmSchemaError> errors, string sourceFilePath) { foreach (var error in errors) { _errors.Add( new CompilerError( error.SchemaLocation ?? sourceFilePath, error.Line, error.Column, error.ErrorCode.ToString(CultureInfo.InvariantCulture), error.Message) { IsWarning = error.Severity == EdmSchemaErrorSeverity.Warning }); } } public bool IsLazyLoadingEnabled(EntityContainer container) { string lazyLoadingAttributeValue; var lazyLoadingAttributeName = MetadataConstants.EDM_ANNOTATION_09_02 + ":LazyLoadingEnabled"; bool isLazyLoading; return !MetadataTools.TryGetStringMetadataPropertySetting(container, lazyLoadingAttributeName, out lazyLoadingAttributeValue) || !bool.TryParse(lazyLoadingAttributeValue, out isLazyLoading) || isLazyLoading; }}public static void ArgumentNotNull<T>(T arg, string name) where T : class{ if (arg == null) { throw new ArgumentNullException(name); }} private static readonly Lazy<System.Resources.ResourceManager> ResourceManager = new Lazy<System.Resources.ResourceManager>( () => new System.Resources.ResourceManager("System.Data.Entity.Design", typeof(MetadataItemCollectionFactory).Assembly), isThreadSafe: true);public static string GetResourceString(string resourceName){ ArgumentNotNull(resourceName, "resourceName"); return ResourceManager.Value.GetString(resourceName, null);}private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName";public IEnumerable<T> GetItemsToGenerate<T>(IEnumerable<GlobalItem> itemCollection) where T: EdmType{ return itemCollection .OfType<T>() .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) .OrderBy(i => i.Name);}#>
生成各種實體類檔案的方法很簡單,只要儲存一下這個EntityOutput.tt檔案,各種實體類檔案即可應聲生成,很爽。
最後生成的檔案如藍線圈圈所示
某個實體擴充類:
// <autogenerated>// This file was generated by T4 code generator EntityOutput.tt.// Any changes made to this file manually will be lost next time the file is regenerated.// </autogenerated>namespace testEF{ public partial class Show : IEntity { public string _ID { get { return Id.ToString(); } } }}
這個模板檔案看起來好複雜,事實上,絕大部分都是自動生成,和拷貝過來的,我自己其實並不懂。
參考文章:
MVC實用架構設計(三)——EF-Code First(3):使用T4模板生成相似程式碼
http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html
EF架構~終於實現了Update方法的統一
http://www.cnblogs.com/lori/archive/2011/07/25/2115982.html