關於代碼生成器的文章網上已經多的不能太多了,在6年前我寫過兩篇文章介紹代碼生成器的,一篇主要代碼生成器的7種模型架構設計思想:也談代碼生成器,另外一篇再談代碼生成器介紹了基於其中一種模型架構的實踐文章,現在回顧一下6年前的文章拿到現在其設計思想也從不過時,呵呵自大了。好了廢話不多說,今天給大家分享一下利用ELinq內置的數據庫元數據模型和T4 模版引擎制作多文件實體代碼生成器。(ELinq:是一個輕量簡單易用的開源Linq ORM數據訪問組件,支持Nullable類型和枚舉類型,支持根據實體類自動建庫建表建關系,支持根據數據庫通過T4模版自動生成實體代碼,對Linq 的謂詞提供了完美的支持,旨在讓絕大部份的主流數據庫都使用 Linq 來進行程序開發,讓開發人員訪問數據庫從SQL中解放出來,易學易用上手快,配置簡單,並且提供了源代碼下載,方便定制。支持多數據庫,目前支持 Access、SQLServer、SqlCE、 SQLite、MySQL、ORACLE,未來還會支持更多的數據庫)
本文使用以下工具:
- VS2010 SP1
- T4 模版引擎
- ELinq 數據庫元數據模型(借助ELinq強大的ORM框架,支持多種數據庫)
- SqlServer 數據庫
操作步驟
- 創建控制台應用程序 Demo
- 通過Nuget添加ELinq 的引用:在Nuget控制台中輸入:install-package ELinq, Nuget會自動的將你引用的庫的這個庫的依賴文件添加到你的項目引用中.
- 配置SqlServer數據庫連接信息。添加App.Config 文件,並添加如下的配置信
<add name="Northwind" connectionString="Data Source=.;Initial Catalog=northwind;Persist Security Info=True;User ID=sa;Password=" providerName="System.Data.SqlClient" />
-
編譯項目,保證ELinq已經輸出到Bin目錄下,為T4 模版准備
- 添加T4 文件,MultipleOutputHelper.ttinclude,該文件的作用是:生成多文件,獲取當前活動項目的信息(配置文件路徑,項目路徑,數據路徑,AppConfig等)
View Code
<#@ template language="C#" debug="True" hostspecific="True" #> <#@ assembly name="System.Core" #><#@ assembly name="EnvDTE" #><#@ assembly name="System.Xml" #><#@ assembly name="System.Xml.Linq" #><#@ assembly name="System.Configuration" #> <#@ import namespace="System" #><#@ import namespace="System.CodeDom" #><#@ import namespace="System.CodeDom.Compiler" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ import namespace="System.Linq" #><#@ import namespace="System.Reflection" #><#@ import namespace="System.Text" #><#@ import namespace="System.Xml.Linq" #><#@ import namespace="Microsoft.VisualStudio.TextTemplating" #><#@ import namespace="System.Configuration" #> <#+ public ConnectionStringSettings GetConnectionStringSettings(string connectionStringName){ if (string.IsNullOrEmpty(connectionStringName)) throw new ArgumentNullException("connectionStringName"); var configFile = new ExeConfigurationFileMap(); configFile.ExeConfigFilename = GetConfigPath(); if (string.IsNullOrEmpty(configFile.ExeConfigFilename)) throw new ArgumentNullException("The project does not contain App.config or Web.config file."); var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None); var connSection = config.ConnectionStrings; var connectionStringSettings = connSection.ConnectionStrings[connectionStringName]; if(connectionStringSettings == null) throw new ArgumentNullException("connectionStringName not exists"); return connectionStringSettings; } public string GetConfigPath(){ EnvDTE.Project project = GetCurrentProject(); foreach (EnvDTE.ProjectItem item in project.ProjectItems){ if (item.Name.Equals("App.config", StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config", StringComparison.InvariantCultureIgnoreCase)) return GetProjectPath() + "\\" + item.Name; } return String.Empty; } public string GetProjectPath(){ EnvDTE.Project project = GetCurrentProject(); System.IO.FileInfo info = new System.IO.FileInfo(project.FullName); return info.Directory.FullName; } public string GetDataDirectory(){ EnvDTE.Project project = GetCurrentProject(); return System.IO.Path.GetDirectoryName(project.FileName) + "\\App_Data\\"; } public EnvDTE.Project GetCurrentProject(){ IServiceProvider _ServiceProvider = (IServiceProvider)Host; if (_ServiceProvider == null) throw new Exception("Host property returned unexpected value (null)"); EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE)); if (dte == null) throw new Exception("Unable to retrieve EnvDTE.DTE"); Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects; if (activeSolutionProjects == null) throw new Exception("DTE.ActiveSolutionProjects returned null"); EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0); if (dteProject == null) throw new Exception("DTE.ActiveSolutionProjects[0] returned null"); return dteProject; } // Manager class records the various blocks so it can split them up class Manager { private class Block { public String Name; public int Start, Length; public bool IncludeInDefault; } private Block currentBlock; private List<Block> files = new List<Block>(); private Block footer = new Block(); private Block header = new Block(); private ITextTemplatingEngineHost host; private StringBuilder template; protected List<String> generatedFileNames = new List<String>(); public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) { return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template); } public void StartNewFile(String name) { if (name == null) throw new ArgumentNullException("name"); CurrentBlock = new Block { Name = name }; } public void StartFooter(bool includeInDefault = true) { CurrentBlock = footer; footer.IncludeInDefault = includeInDefault; } public void StartHeader(bool includeInDefault = true) { CurrentBlock = header; header.IncludeInDefault = includeInDefault; } public void EndBlock() { if (CurrentBlock == null) return; CurrentBlock.Length = template.Length - CurrentBlock.Start; if (CurrentBlock != header && CurrentBlock != footer) files.Add(CurrentBlock); currentBlock = null; } public virtual void Process(bool split, bool sync = true) { if (split) { EndBlock(); String headerText = template.ToString(header.Start, header.Length); String footerText = template.ToString(footer.Start, footer.Length); String outputPath = Path.GetDirectoryName(host.TemplateFile); files.Reverse(); if (!footer.IncludeInDefault) template.Remove(footer.Start, footer.Length); foreach(Block block in files) { String fileName = Path.Combine(outputPath, block.Name); String content = headerText + template.ToString(block.Start, block.Length) + footerText; generatedFileNames.Add(fileName); CreateFile(fileName, content); template.Remove(block.Start, block.Length); } if (!header.IncludeInDefault) template.Remove(header.Start, header.Length); } } protected virtual void CreateFile(String fileName, String content) { if (IsFileContentDifferent(fileName, content)) File.WriteAllText(fileName, content); } public virtual String GetCustomToolNamespace(String fileName) { return null; } public virtual String DefaultProjectNamespace { get { return null; } } protected bool IsFileContentDifferent(String fileName, String newContent) { return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent); } private Manager(ITextTemplatingEngineHost host, StringBuilder template) { this.host = host; this.template = template; } private Block CurrentBlock { get { return currentBlock; } set { if (CurrentBlock != null) EndBlock(); if (value != null) value.Start = template.Length; currentBlock = value; } } private class VSManager: Manager { private EnvDTE.ProjectItem templateProjectItem; private EnvDTE.DTE dte; private Action<String> checkOutAction; private Action<IEnumerable<String>> projectSyncAction; public override String DefaultProjectNamespace { get { return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString(); } } public override String GetCustomToolNamespace(string fileName) { return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString(); } public override void Process(bool split, bool sync) { if (templateProjectItem.ProjectItems == null) return; base.Process(split, sync); if (sync) projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null)); } protected override void CreateFile(String fileName, String content) { if (IsFileContentDifferent(fileName, content)) { CheckoutFileIfRequired(fileName); File.WriteAllText(fileName, content); } } internal VSManager(ITextTemplatingEngineHost host, StringBuilder template) : base(host, template) { var hostServiceProvider = (IServiceProvider) host; if (hostServiceProvider == null) throw new ArgumentNullException("Could not obtain IServiceProvider"); 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); checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName); projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames); } private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) { var keepFileNameSet = new HashSet<String>(keepFileNames); var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>(); var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + "."; foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) projectFiles.Add(projectItem.get_FileNames(0), projectItem); // Remove unused items from the project foreach(var pair in projectFiles) if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix)) pair.Value.Delete(); // Add missing files to the project foreach(String fileName in keepFileNameSet) if (!projectFiles.ContainsKey(fileName)) templateProjectItem.ProjectItems.AddFromFile(fileName); } private void CheckoutFileIfRequired(String fileName) { var sc = dte.SourceControl; if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName)) checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null)); } } } #>
1 <#@ template language="C#" debug="True" hostspecific="True" #> 2 <#@ assembly name="System.Core" 3 #><#@ assembly name="EnvDTE" 4 #><#@ assembly name="System.Xml" 5 #><#@ assembly name="System.Xml.Linq" 6 #><#@ assembly name="System.Configuration" #> 7 <#@ import namespace="System" 8 #><#@ import namespace="System.CodeDom" 9 #><#@ import namespace="System.CodeDom.Compiler" 10 #><#@ import namespace="System.Collections.Generic" 11 #><#@ import namespace="System.IO" 12 #><#@ import namespace="System.Linq" 13 #><#@ import namespace="System.Reflection" 14 #><#@ import namespace="System.Text" 15 #><#@ import namespace="System.Xml.Linq" 16 #><#@ import namespace="Microsoft.VisualStudio.TextTemplating" 17 #><#@ import namespace="System.Configuration" #> 18 <#+ 19 public ConnectionStringSettings GetConnectionStringSettings(string connectionStringName){ 20 if (string.IsNullOrEmpty(connectionStringName)) 21 throw new ArgumentNullException("connectionStringName"); 22 var configFile = new ExeConfigurationFileMap(); 23 configFile.ExeConfigFilename = GetConfigPath(); 24 if (string.IsNullOrEmpty(configFile.ExeConfigFilename)) 25 throw new ArgumentNullException("The project does not contain App.config or Web.config file."); 26 var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None); 27 var connSection = config.ConnectionStrings; 28 var connectionStringSettings = connSection.ConnectionStrings[connectionStringName]; 29 if(connectionStringSettings == null) 30 throw new ArgumentNullException("connectionStringName not exists"); 31 return connectionStringSettings; 32 } 33 public string GetConfigPath(){ 34 EnvDTE.Project project = GetCurrentProject(); 35 foreach (EnvDTE.ProjectItem item in project.ProjectItems){ 36 if (item.Name.Equals("App.config", StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config", StringComparison.InvariantCultureIgnoreCase)) 37 return GetProjectPath() + "\\" + item.Name; 38 } 39 return String.Empty; 40 } 41 public string GetProjectPath(){ 42 EnvDTE.Project project = GetCurrentProject(); 43 System.IO.FileInfo info = new System.IO.FileInfo(project.FullName); 44 return info.Directory.FullName; 45 } 46 public string GetDataDirectory(){ 47 EnvDTE.Project project = GetCurrentProject(); 48 return System.IO.Path.GetDirectoryName(project.FileName) + "\\App_Data\\"; 49 } 50 51 public EnvDTE.Project GetCurrentProject(){ 52 IServiceProvider _ServiceProvider = (IServiceProvider)Host; 53 if (_ServiceProvider == null) 54 throw new Exception("Host property returned unexpected value (null)"); 55 56 EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE)); 57 if (dte == null) 58 throw new Exception("Unable to retrieve EnvDTE.DTE"); 59 60 Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects; 61 if (activeSolutionProjects == null) 62 throw new Exception("DTE.ActiveSolutionProjects returned null"); 63 64 EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0); 65 if (dteProject == null) 66 throw new Exception("DTE.ActiveSolutionProjects[0] returned null"); 67 68 return dteProject; 69 } 70 // Manager class records the various blocks so it can split them up 71 class Manager { 72 private class Block { 73 public String Name; 74 public int Start, Length; 75 public bool IncludeInDefault; 76 } 77 78 private Block currentBlock; 79 private List<Block> files = new List<Block>(); 80 private Block footer = new Block(); 81 private Block header = new Block(); 82 private ITextTemplatingEngineHost host; 83 private StringBuilder template; 84 protected List<String> generatedFileNames = new List<String>(); 85 86 public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) { 87 return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template); 88 } 89 90 public void StartNewFile(String name) { 91 if (name == null) 92 throw new ArgumentNullException("name"); 93 CurrentBlock = new Block { Name = name }; 94 } 95 96 public void StartFooter(bool includeInDefault = true) { 97 CurrentBlock = footer; 98 footer.IncludeInDefault = includeInDefault; 99 } 100 101 public void StartHeader(bool includeInDefault = true) { 102 CurrentBlock = header; 103 header.IncludeInDefault = includeInDefault; 104 } 105 106 public void EndBlock() { 107 if (CurrentBlock == null) 108 return; 109 CurrentBlock.Length = template.Length - CurrentBlock.Start; 110 if (CurrentBlock != header && CurrentBlock != footer) 111 files.Add(CurrentBlock); 112 currentBlock = null; 113 } 114 115 public virtual void Process(bool split, bool sync = true) { 116 if (split) { 117 EndBlock(); 118 String headerText = template.ToString(header.Start, header.Length); 119 String footerText = template.ToString(footer.Start, footer.Length); 120 String outputPath = Path.GetDirectoryName(host.TemplateFile); 121 files.Reverse(); 122 if (!footer.IncludeInDefault) 123 template.Remove(footer.Start, footer.Length); 124 foreach(Block block in files) { 125 String fileName = Path.Combine(outputPath, block.Name); 126 String content = headerText + template.ToString(block.Start, block.Length) + footerText; 127 generatedFileNames.Add(fileName); 128 CreateFile(fileName, content); 129 template.Remove(block.Start, block.Length); 130 } 131 if (!header.IncludeInDefault) 132 template.Remove(header.Start, header.Length); 133 } 134 } 135 136 protected virtual void CreateFile(String fileName, String content) { 137 if (IsFileContentDifferent(fileName, content)) 138 File.WriteAllText(fileName, content); 139 } 140 141 public virtual String GetCustomToolNamespace(String fileName) { 142 return null; 143 } 144 145 public virtual String DefaultProjectNamespace { 146 get { return null; } 147 } 148 149 protected bool IsFileContentDifferent(String fileName, String newContent) { 150 return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent); 151 } 152 153 private Manager(ITextTemplatingEngineHost host, StringBuilder template) { 154 this.host = host; 155 this.template = template; 156 } 157 158 private Block CurrentBlock { 159 get { return currentBlock; } 160 set { 161 if (CurrentBlock != null) 162 EndBlock(); 163 if (value != null) 164 value.Start = template.Length; 165 currentBlock = value; 166 } 167 } 168 169 private class VSManager: Manager { 170 private EnvDTE.ProjectItem templateProjectItem; 171 private EnvDTE.DTE dte; 172 private Action<String> checkOutAction; 173 private Action<IEnumerable<String>> projectSyncAction; 174 175 public override String DefaultProjectNamespace { 176 get { 177 return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString(); 178 } 179 } 180 181 public override String GetCustomToolNamespace(string fileName) { 182 return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString(); 183 } 184 185 public override void Process(bool split, bool sync) { 186 if (templateProjectItem.ProjectItems == null) 187 return; 188 base.Process(split, sync); 189 if (sync) 190 projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null)); 191 } 192 193 protected override void CreateFile(String fileName, String content) { 194 if (IsFileContentDifferent(fileName, content)) { 195 CheckoutFileIfRequired(fileName); 196 File.WriteAllText(fileName, content); 197 } 198 } 199 200 internal VSManager(ITextTemplatingEngineHost host, StringBuilder template) 201 : base(host, template) { 202 var hostServiceProvider = (IServiceProvider) host; 203 if (hostServiceProvider == null) 204 throw new ArgumentNullException("Could not obtain IServiceProvider"); 205 dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE)); 206 if (dte == null) 207 throw new ArgumentNullException("Could not obtain DTE from host"); 208 templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile); 209 checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName); 210 projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames); 211 } 212 213 private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) { 214 var keepFileNameSet = new HashSet<String>(keepFileNames); 215 var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>(); 216 var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + "."; 217 foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) 218 projectFiles.Add(projectItem.get_FileNames(0), projectItem); 219 220 // Remove unused items from the project 221 foreach(var pair in projectFiles) 222 if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix)) 223 pair.Value.Delete(); 224 225 // Add missing files to the project 226 foreach(String fileName in keepFileNameSet) 227 if (!projectFiles.ContainsKey(fileName)) 228 templateProjectItem.ProjectItems.AddFromFile(fileName); 229 } 230 231 private void CheckoutFileIfRequired(String fileName) { 232 var sc = dte.SourceControl; 233 if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName)) 234 checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null)); 235 } 236 } 237 } #>
- 添加T4文件:NorthwindContext.tt
View Code
<#@ template debug="True" hostspecific="True" language="C#" #> <#@ Include File="MultipleOutputHelper.ttinclude" #> <#@ Assembly Name="$(TargetDir)NLite.dll" #> <#@ Assembly Name="$(TargetDir)ELinq.dll" #> <#@ Assembly Name="System.Data" #> <#@ Import Namespace="NLite.Data" #> <#@ Import Namespace="NLite.Data.CodeGeneration" #> <#@ output extension=".cs" #> <# var @namespace = "NLite.Data.CodeGenerationDemo"; var connectionStringName = "Northwind"; var dbContextName = Host.TemplateFile.Split('\\')[Host.TemplateFile.Split('\\').Length - 1].TrimEnd('.', 't'); var connectionStringSetting = GetConnectionStringSettings(connectionStringName); var connectionString = connectionStringSetting.ConnectionString; var dbProviderName = connectionStringSetting.ProviderName; var dbConfiguration = DbConfiguration.Configure(connectionString, dbProviderName); var databaseSchema = dbConfiguration.Schema; var manager = Manager.Create(Host, GenerationEnvironment); manager.StartHeader(); #> using System; using System.Collections.Generic; using System.Linq; using NLite.Data; namespace <#= @namespace #> { <# manager.EndBlock(); #> using NLite.Reflection; public partial class <#= dbContextName #>:DbContext { //連接字符串名稱:基於Config文件中連接字符串的配置 const string connectionStringName = "<#= connectionStringName #>"; //構造dbConfiguration 對象 static DbConfiguration dbConfiguration; static <#= dbContextName #>() { dbConfiguration = DbConfiguration .Configure(connectionStringName) .SetSqlLogger(() =>SqlLog.Debug) .AddFromAssemblyOf<<#= dbContextName #>>(t=>t.HasAttribute<TableAttribute>(false)) ; } public <#= dbContextName #>():base(dbConfiguration){} <#foreach (var tb in databaseSchema.Tables.Union(databaseSchema.Views)){#> public IDbSet<<#=NamingConversion.Default.ClassName(tb.TableName) #>> <#= NamingConversion.Default.QueryableName(tb.TableName) #> { get; private set; } <#}#> } <#foreach (var tb in databaseSchema.Tables){ manager.StartNewFile(NamingConversion.Default.ClassName(tb.TableName) + ".generated.cs");#> [Table("<#= tb.TableName #>")] public partial class <#= NamingConversion.Default.ClassName( tb.TableName) #> { <#foreach (var col in tb.PrimaryKeys){#> [Id("<#= col.ColumnName#>",IsDbGenerated=<#= col.IsGenerated.ToString().ToLower() #>)] public <#= NamingConversion.Default.DataType(col) #> <#= NamingConversion.Default.PropertyName(col.ColumnName) #> { get;set; } <#}#> <#foreach (var col in tb.Columns){#> [Column("<#= col.ColumnName#>")] public <#= NamingConversion.Default.DataType(col) #> <#= NamingConversion.Default.PropertyName(col.ColumnName) #> { get;set; } <#}#> <#foreach (var fk in tb.ForeignKeys){#> [ManyToOne(ThisKey="<#= NamingConversion.Default.PropertyName( fk.ThisKey.ColumnName) #>",OtherKey="<#= NamingConversion.Default.PropertyName(fk.OtherKey.ColumnName) #>")] public <#= NamingConversion.Default.ClassName(fk.OtherTable.TableName) #> <#= NamingConversion.Default.ManyToOneName(fk) #> { get;set; } <#}#> <#foreach (var fk in tb.Children){#> [OneToMany(ThisKey="<#= NamingConversion.Default.PropertyName( fk.ThisKey.ColumnName) #>",OtherKey="<#= NamingConversion.Default.PropertyName(fk.OtherKey.ColumnName) #>")] public IList<<#= NamingConversion.Default.ClassName(fk.OtherTable.TableName) #>> <#= NamingConversion.Default.QueryableName(fk.OtherTable.TableName) #> { get;set; } <#}#> } <# } manager.EndBlock(); foreach (var tb in databaseSchema.Views){ manager.StartNewFile(NamingConversion.Default.ClassName(tb.TableName) + ".generated.cs");#> [Table("<#= tb.TableName #>",Readonly=true)] public partial class <#= NamingConversion.Default.ClassName( tb.TableName) #> { <#foreach (var col in tb.Columns){#> [Column("<#= col.ColumnName#>")] public <#= col.Type.Name #> <#= NamingConversion.Default.PropertyName(col.ColumnName) #> { get;set; } <#}#> } <# } manager.EndBlock(); manager.StartFooter(); #> } <# manager.EndBlock(); manager.Process(true); #>
- 保存一下NorthwindContext.tt 文件,系統會自動創建實體、實體間的關系(一對多,多對一)和DbContext, 見下圖
8. 運行代碼查看
補充
1. ELinq 數據庫Schema元數據結構圖(只要配置好了DbConfiguration對象,只需要調用其Schema屬性就會自動得到如下Schema數據
2. ELinq 還提供了表名到類名、列名到屬性等轉換約定,針對特殊情況可以自行定制
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NLite.Data.Schema; namespace NLite.Data.CodeGeneration { /// <summary> /// 命名約定 /// </summary> public static class NamingConversion { /// <summary> /// 缺省命名約定 /// </summary> public static readonly INamingConversion Default = new DefaultNamingConversion(); } /// <summary> /// 命名約定 /// </summary> public interface INamingConversion { /// <summary> /// 表名轉集合名 /// </summary> /// <param name="tableName"></param> /// <returns></returns> string QueryableName(string tableName); /// <summary> /// 表名轉類名 /// </summary> /// <param name="tableName"></param> /// <returns></returns> string ClassName(string tableName); /// <summary> /// 列名轉字段名 /// </summary> /// <param name="columnName"></param> /// <returns></returns> string FieldName(string columnName); /// <summary> /// 列名屬性名轉 /// </summary> /// <param name="columnName"></param> /// <returns></returns> string PropertyName(string columnName); /// <summary> /// 得到類的數據類型 /// </summary> /// <param name="col"></param> /// <returns></returns> string DataType(IColumnSchema col); /// <summary> /// 得到外鍵對應的導航屬性名稱 /// </summary> /// <param name="fk"></param> /// <returns></returns> string ManyToOneName(IForeignKeySchema fk); } }
3. 默認情況下自定義DbContext名稱和T4模版文件的名稱一致
4. 如何修該代碼生成的命名空間以及數據庫配置
總結
最后附上Demo代碼,大家可以修改一下配置文件,即可支持其它數據庫的代碼生成,也可以修改T4 模版DIY 自己的代碼生成器!隨后會發布基於Nuget安裝方式的T4 模版代碼生成器包,供大家方便使用、
技術支持:
- 官方網站
- Nuge 下載頁面
- ORM組件 ELinq系列
- ORM組件 ELinq 更新日志
- ORM組件 ELinq 使用答疑
- 在我的博客留言,我會盡可能地抽時間來答復大家的問題。
- 加入 ELinq用戶的 QQ群(271342583)。
新年伊始,祝大家春節愉快,萬事如意,謝謝大家的閱讀,麻煩大伙點一下推薦,再次謝謝大家。 ^_^