• 新年首作ELinq+T4模版引擎制作多文件实体代码生成器


      关于代码生成器的文章网上已经多的不能太多了,在6年前我写过两篇文章介绍代码生成器的,一篇主要代码生成器的7种模型架构设计思想:也谈代码生成器,另外一篇再谈代码生成器介绍了基于其中一种模型架构的实践文章,现在回顾一下6年前的文章拿到现在其设计思想也从不过时,呵呵自大了。好了废话不多说,今天给大家分享一下利用ELinq内置的数据库元数据模型和T4 模版引擎制作多文件实体代码生成器。(ELinq:是一个轻量简单易用的开源Linq ORM数据访问组件,支持Nullable类型和枚举类型,支持根据实体类自动建库建表建关系,支持根据数据库通过T4模版自动生成实体代码,对Linq 的谓词提供了完美的支持,旨在让绝大部份的主流数据库都使用 Linq 来进行程序开发,让开发人员访问数据库从SQL中解放出来,易学易用上手快,配置简单,并且提供了源代码下载,方便定制。支持多数据库,目前支持 Access、SQLServer、SqlCE、  SQLite、MySQL、ORACLE,未来还会支持更多的数据库

      本文使用以下工具:

    1. VS2010 SP1
    2. T4 模版引擎
    3. ELinq 数据库元数据模型(借助ELinq强大的ORM框架,支持多种数据库)
    4. SqlServer 数据库

        操作步骤

    1.   创建控制台应用程序 Demo
    2.   通过Nuget添加ELinq 的引用:在Nuget控制台中输入:install-package ELinq, Nuget会自动的将你引用的库的这个库的依赖文件添加到你的项目引用中.
    3.   配置SqlServer数据库连接信息。添加App.Config 文件,并添加如下的配置信
      <add name="Northwind" connectionString="Data Source=.;Initial Catalog=northwind;Persist Security Info=True;User ID=sa;Password="
      providerName="System.Data.SqlClient" />
    4. 编译项目,保证ELinq已经输出到Bin目录下,为T4 模版准备

    5. 添加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 } #>
    6. 添加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);
      #>
    7. 保存一下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 模版代码生成器包,供大家方便使用、

    技术支持:

    1. 官方网站
    2. Nuge 下载页面
    3. ORM组件 ELinq系列
    4. ORM组件 ELinq 更新日志
    5. ORM组件 ELinq 使用答疑
    6. 在我的博客留言,我会尽可能地抽时间来答复大家的问题。
    7. 加入 ELinq用户的 QQ群(271342583)。

       新年伊始,祝大家春节愉快,万事如意,谢谢大家的阅读,麻烦大伙点一下推荐,再次谢谢大家。 ^_^

  • 相关阅读:
    [转] Web前端优化之 Flash篇
    [转] Web 前端优化最佳实践之 Mobile(iPhone) 篇
    [转] Web前端优化之 图片篇
    [转] Web前端优化之 Javascript篇
    [转] Web前端优化之 CSS篇
    react事件获取元素
    Nodejs学习笔记02【module】
    Nodejs学习笔记01【EventEmitter】
    javascript运算符优先级
    jQuery-placeholder
  • 原文地址:https://www.cnblogs.com/netcasewqs/p/2912838.html
Copyright © 2020-2023  润新知