1.在你要生成的项目里面在根目录下面添加CodeTemplates文件夹,并在该文件夹下面创建子文件夹ReverseEngineerCodeFirst
2.在ReverseEngineerCodeFirst目录下面新建一下几个文件:
- Context.tt
-
1 <#@ template hostspecific="true" language="C#" #> 2 <#@ include file="EF.Utility.CS.ttinclude" #><#@ 3 output extension=".cs" encoding="UTF-8" #><# 4 5 var efHost = (EfTextTemplateHost)Host; 6 var code = new CodeGenerationTools(this); 7 8 #> 9 //------------------------------------------------------------------------------ 10 // <auto-generated> 11 // 此代码由工具生成。 12 // 对此文件的更改可能会导致不正确的行为,并且如果 13 // 重新生成代码,这些更改将会丢失。 14 // </auto-generated> 15 // <copyright file="<#= efHost.EntityContainer.Name #>.cs"> 16 // Copyright(c)2015 rights reserved. 17 // CLR版本:4.0.30319.239 18 // 开发组织:李文学@上海同岩土木科技工程有限公司 19 // 所属工程:TY.* 20 // 生成时间:<#= DateTime.Now.ToString("yyyy-MM-dd HH:mm") #> 21 // </copyright> 22 //------------------------------------------------------------------------------ 23 24 using System.Data.Entity; 25 using System.Data.Entity.Infrastructure; 26 using <#= code.EscapeNamespace(efHost.MappingNamespace) #>; 27 28 namespace <#= code.EscapeNamespace(efHost.Namespace) #> 29 { 30 public partial class <#= efHost.EntityContainer.Name #> : DbContext 31 { 32 static <#= efHost.EntityContainer.Name #>() 33 { 34 Database.SetInitializer<<#= efHost.EntityContainer.Name #>>(null); 35 } 36 37 public <#= efHost.EntityContainer.Name #>() 38 : base("Name=<#= efHost.EntityContainer.Name #>") 39 { 40 } 41 42 <# 43 var summary=""; 44 foreach (var set in efHost.EntityContainer.BaseEntitySets.OfType<EntitySet>()) 45 { 46 if(set.Documentation !=null && set.Documentation.Summary!=null) 47 summary=set.Documentation.Summary; 48 49 else if(set.Documentation !=null && set.Documentation.LongDescription!=null) 50 summary=set.Documentation.LongDescription; 51 else 52 summary=string.Format("[{0}]", set.ElementType.Name); 53 #> 54 /// <summary> 55 /// <#= summary #> 56 /// </summary> 57 public DbSet<<#= set.ElementType.Name #>> <#= set.Name #> { get; set; } 58 <# 59 } 60 #> 61 62 protected override void OnModelCreating(DbModelBuilder modelBuilder) 63 { 64 <# 65 foreach (var set in efHost.EntityContainer.BaseEntitySets.OfType<EntitySet>()) 66 { 67 #> 68 modelBuilder.Configurations.Add(new <#= set.ElementType.Name #>Map()); 69 <# 70 } 71 #> 72 } 73 } 74 }
- Entity.tt
-
1 <#@ template hostspecific="true" language="C#" #> 2 <#@ include file="EF.Utility.CS.ttinclude" #><#@ 3 output extension=".cs" encoding="UTF-8" #><# 4 5 var efHost = (EfTextTemplateHost)Host; 6 var code = new CodeGenerationTools(this); 7 8 #> 9 //------------------------------------------------------------------------------ 10 // <auto-generated> 11 // 此代码由工具生成。 12 // 对此文件的更改可能会导致不正确的行为,并且如果 13 // 重新生成代码,这些更改将会丢失。 14 // </auto-generated> 15 // <copyright file="<#= efHost.EntityType.Name #>.cs"> 16 // Copyright(c)2015 rights reserved. 17 // CLR版本:4.0.30319.239 18 // 开发组织:李文学@上海同岩土木科技工程有限公司 19 // 所属工程:TY.* 20 // 生成时间:<#= DateTime.Now.ToString("yyyy-MM-dd HH:mm") #> 21 // </copyright> 22 //------------------------------------------------------------------------------ 23 24 using System; 25 using System.Collections.Generic; 26 using XXXX.EF; 27 using XXXX.EF.Base; 28 using XXXX.ToolT4; 29 30 <# 31 var summary=""; 32 var entity=efHost.EntityType; 33 if(entity.Documentation !=null && entity.Documentation.Summary!=null) 34 summary=entity.Documentation.Summary; 35 36 else if(entity.Documentation !=null && entity.Documentation.LongDescription!=null) 37 summary=entity.Documentation.LongDescription; 38 else 39 summary=string.Format("[{0}]", entity.Name); 40 41 #> 42 43 namespace <#= code.EscapeNamespace(efHost.Namespace) #> 44 { 45 /// <summary> 46 /// <#= summary#> 47 /// </summary> 48 [Serializable] 49 public partial class <#= efHost.EntityType.Name #> : BaseEntity 50 { 51 <# 52 var collectionNavigations = efHost.EntityType.NavigationProperties.Where( 53 np => np.DeclaringType == efHost.EntityType 54 && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); 55 56 // Add a ctor to initialize any collections 57 if (collectionNavigations.Any()) 58 { 59 #> 60 /// <summary> 61 /// 构造函数 62 /// </summary> 63 public <#= code.Escape(efHost.EntityType) #>() 64 { 65 <# 66 foreach (var navProperty in collectionNavigations) 67 { 68 #> 69 this.<#= code.Escape(navProperty) #> = new List<<#= code.Escape(navProperty.ToEndMember.GetEntityType()) #>>(); 70 <# 71 } 72 #> 73 } 74 75 <# 76 } 77 78 foreach (var property in efHost.EntityType.Properties) 79 { 80 var typeUsage = code.Escape(property.TypeUsage); 81 82 // Fix-up spatial types for EF6 83 if (efHost.EntityFrameworkVersion >= new Version(6, 0) 84 && typeUsage.StartsWith("System.Data.Spatial.")) 85 { 86 typeUsage = typeUsage.Replace( 87 "System.Data.Spatial.", 88 "System.Data.Entity.Spatial."); 89 } 90 if(property.Documentation !=null && property.Documentation.Summary!=null) 91 summary=property.Documentation.Summary; 92 93 else if(property.Documentation !=null && property.Documentation.LongDescription!=null) 94 summary=property.Documentation.LongDescription; 95 else 96 summary=string.Format("[{0}]", property.Name); 97 98 #> 99 /// <summary> 100 /// <#= summary#> 101 /// </summary> 102 <#= Accessibility.ForProperty(property) #> <#= typeUsage #> <#= code.Escape(property) #> { get; set; } 103 <# 104 } 105 106 foreach (var navProperty in efHost.EntityType.NavigationProperties.Where(np => np.DeclaringType == efHost.EntityType)) 107 { 108 if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) 109 { 110 #> 111 /// <summary> 112 /// 导航集合:<#= navProperty#> 113 /// </summary> 114 public virtual ICollection<<#= code.Escape(navProperty.ToEndMember.GetEntityType()) #>> <#= code.Escape(navProperty) #> { get; set; } 115 <# 116 } 117 else 118 { 119 #> 120 /// <summary> 121 /// 导航属性:<#= navProperty#> 122 /// </summary> 123 public virtual <#= code.Escape(navProperty.ToEndMember.GetEntityType()) #> <#= code.Escape(navProperty) #> { get; set; } 124 <# 125 } 126 } 127 #> 128 } 129 }
- Mapping.tt
-
<#@ template hostspecific="true" language="C#" #> <#@ include file="EF.Utility.CS.ttinclude" #><#@ output extension=".cs" encoding="UTF-8" #><# var efHost = (EfTextTemplateHost)Host; var code = new CodeGenerationTools(this); #> //------------------------------------------------------------------------------ // <auto-generated> // 此代码由工具生成。 // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // </auto-generated> // <copyright file="<#= efHost.EntityType.Name #>Map.cs"> // Copyright(c)2015 rights reserved. // CLR版本:4.0.30319.239 // 开发组织:李文学@上海同岩土木科技工程有限公司 // 所属工程:TY.* // 生成时间:<#= DateTime.Now.ToString("yyyy-MM-dd HH:mm") #> // </copyright> //------------------------------------------------------------------------------ <# if (efHost.EntityFrameworkVersion >= new Version(4, 4)) { #> using System.ComponentModel.DataAnnotations.Schema; <# } else { #> using System.ComponentModel.DataAnnotations; <# } #> using System.Data.Entity.ModelConfiguration; namespace <#= code.EscapeNamespace(efHost.Namespace) #> { public class <#= efHost.EntityType.Name #>Map : EntityTypeConfiguration<<#= efHost.EntityType.Name #>> { public <#= efHost.EntityType.Name #>Map() { // Primary Key <# if (efHost.EntityType.KeyMembers.Count() == 1) { #> this.HasKey(t => t.<#= efHost.EntityType.KeyMembers.Single().Name #>); <# } else { #> this.HasKey(t => new { <#= string.Join(", ", efHost.EntityType.KeyMembers.Select(m => "t." + m.Name)) #> }); <# } #> // Properties <# foreach (var prop in efHost.EntityType.Properties) { var type = (PrimitiveType)prop.TypeUsage.EdmType; var isKey = efHost.EntityType.KeyMembers.Contains(prop); var storeProp = efHost.PropertyToColumnMappings[prop]; var sgpFacet = storeProp.TypeUsage.Facets.SingleOrDefault(f => f.Name == "StoreGeneratedPattern"); var storeGeneratedPattern = sgpFacet == null ? StoreGeneratedPattern.None : (StoreGeneratedPattern)sgpFacet.Value; var configLines = new List<string>(); if (type.ClrEquivalentType == typeof(int) || type.ClrEquivalentType == typeof(decimal) || type.ClrEquivalentType == typeof(short) || type.ClrEquivalentType == typeof(long)) { if (isKey && storeGeneratedPattern != StoreGeneratedPattern.Identity) { configLines.Add(".HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)"); } else if ((!isKey || efHost.EntityType.KeyMembers.Count > 1) && storeGeneratedPattern == StoreGeneratedPattern.Identity) { configLines.Add(".HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)"); } } if (type.ClrEquivalentType == typeof(string) || type.ClrEquivalentType == typeof(byte[])) { if (!prop.Nullable) { configLines.Add(".IsRequired()"); } var unicodeFacet = (Facet)prop.TypeUsage.Facets.SingleOrDefault(f => f.Name == "IsUnicode"); if(unicodeFacet != null && !(bool)unicodeFacet.Value) { configLines.Add(".IsUnicode(false)"); } var fixedLengthFacet = (Facet)prop.TypeUsage.Facets.SingleOrDefault(f => f.Name == "FixedLength"); if (fixedLengthFacet != null && (bool)fixedLengthFacet.Value) { configLines.Add(".IsFixedLength()"); } var maxLengthFacet = (Facet)prop.TypeUsage.Facets.SingleOrDefault(f => f.Name == "MaxLength"); if (maxLengthFacet != null && !maxLengthFacet.IsUnbounded) { configLines.Add(string.Format(".HasMaxLength({0})", maxLengthFacet.Value)); if (storeGeneratedPattern == StoreGeneratedPattern.Computed && type.ClrEquivalentType == typeof(byte[]) && (int)maxLengthFacet.Value == 8) { configLines.Add(".IsRowVersion()"); } } } if(configLines.Any()) { #> this.Property(t => t.<#= prop.Name #>) <#= string.Join("\r\n ", configLines) #>; <# } } var tableSet = efHost.TableSet; var tableName = (string)tableSet.MetadataProperties["Table"].Value ?? tableSet.Name; var schemaName = (string)tableSet.MetadataProperties["Schema"].Value; #> // Table & Column Mappings this.ToTable("<#= tableName #>"); <# foreach (var property in efHost.EntityType.Properties) { if(property.TypeUsage.EdmType is PrimitiveType && ((PrimitiveType)property.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Decimal) { var jdLen = property.TypeUsage.Facets[2].Value; var jdXsv = property.TypeUsage.Facets[3].Value; #> this.Property(t => t.<#=property.Name #>).HasColumnName("<#=efHost.PropertyToColumnMappings[property].Name #>").HasPrecision(<#=jdLen#>,<#=jdXsv#>); <# } else{ #> this.Property(t => t.<#=property.Name #>).HasColumnName("<#=efHost.PropertyToColumnMappings[property].Name #>"); <# } } // Find m:m relationshipsto configure var manyManyRelationships = efHost.EntityType.NavigationProperties .Where(np => np.DeclaringType == efHost.EntityType && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many && np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many && np.RelationshipType.RelationshipEndMembers.First() == np.FromEndMember); // <- ensures we only configure from one end // Find FK relationships that this entity is the dependent of var fkRelationships = efHost.EntityType.NavigationProperties .Where(np => np.DeclaringType == efHost.EntityType && ((AssociationType)np.RelationshipType).IsForeignKey && ((AssociationType)np.RelationshipType).ReferentialConstraints.Single().ToRole == np.FromEndMember); if(manyManyRelationships.Any() || fkRelationships.Any()) { #> // Relationships <# foreach (var navProperty in manyManyRelationships) { var otherNavProperty = navProperty.ToEndMember.GetEntityType().NavigationProperties.Where(n => n.RelationshipType == navProperty.RelationshipType && n != navProperty).Single(); var association = (AssociationType)navProperty.RelationshipType; var mapping = efHost.ManyToManyMappings[association]; var item1 = mapping.Item1; var mappingTableName = (string)mapping.Item1.MetadataProperties["Table"].Value ?? item1.Name; var mappingSchemaName = (string)item1.MetadataProperties["Schema"].Value; // Need to ensure that FKs are decalred in the same order as the PK properties on each principal type var leftType = (EntityType)navProperty.DeclaringType; var leftKeyMappings = mapping.Item2[navProperty.FromEndMember]; var leftColumns = string.Join(", ", leftType.KeyMembers.Select(m => "\"" + leftKeyMappings[m] + "\"")); var rightType = (EntityType)otherNavProperty.DeclaringType; var rightKeyMappings = mapping.Item2[otherNavProperty.FromEndMember]; var rightColumns = string.Join(", ", rightType.KeyMembers.Select(m => "\"" + rightKeyMappings[m] + "\"")); #> this.HasMany(t => t.<#= code.Escape(navProperty) #>) .WithMany(t => t.<#= code.Escape(otherNavProperty) #>) .Map(m => { m.ToTable("<#= mappingTableName #>"); m.MapLeftKey(<#= leftColumns #>); m.MapRightKey(<#= rightColumns #>); }); <# } foreach (var navProperty in fkRelationships) { var otherNavProperty = navProperty.ToEndMember.GetEntityType().NavigationProperties.Where(n => n.RelationshipType == navProperty.RelationshipType && n != navProperty).Single(); var association = (AssociationType)navProperty.RelationshipType; if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) { #> this.HasRequired(t => t.<#= code.Escape(navProperty) #>) <# } else { #> this.HasOptional(t => t.<#= code.Escape(navProperty) #>) <# } if(navProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) { #> .WithMany(t => t.<#= code.Escape(otherNavProperty) #>) <# if(association.ReferentialConstraints.Single().ToProperties.Count == 1) { #> .HasForeignKey(d => d.<#= association.ReferentialConstraints.Single().ToProperties.Single().Name #>); <# } else { #> .HasForeignKey(d => new { <#= string.Join(", ", association.ReferentialConstraints.Single().ToProperties.Select(p => "d." + p.Name)) #> }); <# } } else { // NOTE: We can assume that this is a required:optional relationship // as EDMGen will never create an optional:optional relationship // because everything is one:many except PK-PK relationships which must be required #> .WithOptional(t => t.<#= code.Escape(otherNavProperty) #>); <# } } #> <# } #> } } }
- BaseEntity.cs
-
using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace XXXX.EF.Base { /// <summary> /// 抽象实体类型:可用作DbFirst使用以作为Entiry基类 /// </summary> public abstract class BaseEntity { } }
- T4ModelInfo.cs
-
using System; using System.Collections.Generic; using System.ComponentModel; using System.Reflection; namespace XXXX.ToolT4 { /// <summary> /// T4实体模型信息类 /// </summary> public class T4ModelInfo { /// <summary> /// 获取 模型所在模块名称 /// </summary> public string ModuleName { get; private set; } /// <summary> /// 获取 模型名称 /// </summary> public string Name { get; private set; } /// <summary> /// 获取 模型描述 /// </summary> public string Description { get; private set; } /// <summary> /// 属性集合 /// </summary> public IEnumerable<PropertyInfo> Properties { get; private set; } public T4ModelInfo(Type modelType) { var @namespace = modelType.Namespace; if (@namespace == null) { return; } var index = @namespace.LastIndexOf(‘.‘) + 1; ModuleName = @namespace.Substring(index, @namespace.Length - index); Name = modelType.Name; var descAttributes = modelType.GetCustomAttributes(typeof(DescriptionAttribute), true); Description = descAttributes.Length == 1 ? ((DescriptionAttribute)descAttributes[0]).Description : Name; Properties = modelType.GetProperties(); } } }
有了上传代码借助于EntityReverseCode就可以生成我们需要的实体类,实体映射类