前言
我们都知道EF可以生成Dbmodel,系统生成的Model有时候并不是我们想要的,如何我们要生成自己的Model,那么久需要我们手动的去修改T4模版,T4是对“Text Template Transformation Toolkit”(4个T)的简称。如果你对T4不怎么了解可以去看蒋金楠(Artech)文章从数据到代码——基于T4的代码生成方式。
1.0先看看我们要达到的效果图吧
2.0首先我们来修改T4模版吧
打开T4模版,找到代码 WriteHeader(codeStringGenerator, fileManager);
我们首先定义变量(图中黄色代码为我们自己添加的代码)
WriteHeader(codeStringGenerator, fileManager); string summary=string.Empty; 定义变量 foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { fileManager.StartNewFile(entity.Name + ".cs"); BeginNamespace(code); if(entity.Documentation !=null && entity.Documentation.Summary!=null) summary=entity.Documentation.Summary; else summary=entity.Name; #> <#=codeStringGenerator.UsingDirectives(inHeader: false)#> using System.ComponentModel.DataAnnotations; 导入你需要的命名空间 /// <summary> /// <#= summary#>给类加注释 /// </summary> [Serializable] <#=codeStringGenerator.EntityClassOpening(entity)#>
看看效果图如下:
类上面的注释已经加好了,接下来就是删除构造函数,删除以下代码即可:
public <#=code.Escape(entity)#>() { <# foreach (var edmProperty in propertiesWithDefaultValues) { #> this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; <# } foreach (var navigationProperty in collectionNavigationProperties) { #> this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); <# } foreach (var complexProperty in complexProperties) { #> this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); <# } #> }
接下来我们把这些可空类型还原成本来面目,已经去掉virtual关键字,修改代码如下:
public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) { if (edmType == null) { return null; } var collectionType = edmType as CollectionType; if (collectionType != null) { return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); } var typeName = _code.Escape(edmType.MetadataProperties .Where(p => p.Name == ExternalTypeNameAttributeName) .Select(p => (string)p.Value) .FirstOrDefault()) ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : _code.Escape(edmType)); if (edmType is StructuralType) { return typeName; } if (edmType is SimpleType) { var clrType = UnderlyingClrType(edmType); if (!IsEnumType(edmType)) { typeName = _code.Escape(clrType); } typeName = FixNamespaces(typeName); return clrType.IsValueType && isNullable == true ? // String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) :原来的代码
String.Format(CultureInfo.InvariantCulture, "{0}?", typeName) :自己修改的代码
typeName; } throw new ArgumentException("edmType"); }
public string NavigationProperty(NavigationProperty navigationProperty) { var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType()); return string.Format( CultureInfo.InvariantCulture, "public {1} {2} {{ {3}get; {4}set; }}", AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)), navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, _code.Escape(navigationProperty), _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)), _code.SpaceAfter(Accessibility.ForSetter(navigationProperty))); }
接下来来给属性上添加注释:(橙色代码删除,皇色代码添加)
/// <summary> /// <#= summary#> /// </summary> [Serializable] <#=codeStringGenerator.EntityClassOpening(entity)#> { <# var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity); var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity); var complexProperties = typeMapper.GetComplexProperties(entity); if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) { #> <# }删除掉代码 var simpleProperties = typeMapper.GetSimpleProperties(entity); if (simpleProperties.Any()) { foreach (var edmProperty in simpleProperties) { if (edmProperty.Documentation != null && edmProperty.Documentation.Summary != null) { if(!entity.KeyMembers.Contains(edmProperty.Name)) summary=edmProperty.Documentation.Summary.ToLower().Replace("id","名称"); else summary=edmProperty.Documentation.Summary; } else { summary=""; } #> <# //if(edmProperty.Name.ToLower() == "id") // continue;var a=edmProperty.Nullable; var keyName=""; if(entity.KeyMembers.Contains(edmProperty.Name)) keyName="[Key]"; var required=""; if(!edmProperty.Nullable) required="[Required(ErrorMessage = "请输入{0}")]"; string facetName = "MaxLength"; var lengthDes=""; var stringLengthDes=""; int maxLength = 0; if (code.Escape(edmProperty.TypeUsage).ToLower().Contains("string") && Int32.TryParse(edmProperty.TypeUsage.Facets[facetName].Value.ToString(), out maxLength)){ lengthDes="[MaxLength("+maxLength+")]"; stringLengthDes="[StringLength("+maxLength+")]"; } var dataType=""; if (code.Escape(edmProperty.TypeUsage).ToLower().Contains("datetime")) dataType="[DataType(DataType.DateTime)]"; else if (edmProperty.Name.ToLower().Contains("password")) dataType="[DataType(DataType.Password)]"; #> /// <summary> /// <#= summary#> /// </summary> <# if(!string.IsNullOrWhiteSpace(required)){ #> <#= required #> <# } if(!string.IsNullOrWhiteSpace(summary)){ #> <#= "[Display(Name = ""+summary+"")]" #> <# } if(!string.IsNullOrWhiteSpace(lengthDes)){ #> <#= lengthDes #> <# } if(!string.IsNullOrWhiteSpace(stringLengthDes)){ #> <#= stringLengthDes #> <# } if(!string.IsNullOrWhiteSpace(dataType)){ #> <#= dataType #> <# } if(!string.IsNullOrWhiteSpace(keyName)){ #> <#= keyName #> <# } #> <#=codeStringGenerator.Property(edmProperty)#>
效果基本已经差不多,可是这里为什么没有注释,园子里已经有其他文章来处理这个问题:
1.0EF架构~将数据库注释添加导入到模型实体类中 2.0entity framework框架生成摘要文档为空(没有元数据文档可用)的bug解决方案
按照步骤做了,可是问题还是没有解决,怎么办,其实根本原因是:
主要原因是这里的摘要没有数据。不断的尝试啊,entity framework框架生成摘要文档为空(没有元数据文档可用)的bug解决方案 试了几次还是没有从根本上解决问题,怎么办了...
3.0解决bug
没办法我们查看EFTSQLDocumentation.Generator的源码终于找到问题所在
public String ConnectionString { get; set; } public String InputFileName { get; set; } public String OutputFileName { get; set; } private SqlConnection _connection; public Program(String connectionString, String inputFileName, String outputFileName) { this.ConnectionString = connectionString; this.InputFileName = inputFileName; this.OutputFileName = outputFileName; this._connection = new SqlConnection(connectionString); this._connection.Open(); } public void Dispose() { this._connection.Dispose(); } private void CreateDocumentation() { XDocument doc = XDocument.Load(this.InputFileName); IEnumerable<XElement> entityTypeElements = doc.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}EntityType"); int i = 0; foreach (XElement entityTypeElement in entityTypeElements) { String tableName = entityTypeElement.Attribute("Name").Value; IEnumerable<XElement> propertyElements = entityTypeElement.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Property"); Console.Clear(); Console.WriteLine("Analyzing table {0} of {1}", i++, entityTypeElements.Count()); Console.WriteLine(" => TableName : {0}" + " => property count : {1}", tableName, propertyElements.Count()); this.AddNodeDocumentation(entityTypeElement, GetTableDocumentation(tableName)); foreach (XElement propertyElement in propertyElements) { String columnName = propertyElement.Attribute("Name").Value; this.AddNodeDocumentation(propertyElement, GetColumnDocumentation(tableName, columnName)); } } Console.WriteLine("Writing result to {0}", this.OutputFileName); if (File.Exists(this.OutputFileName)) File.Delete(this.OutputFileName); doc.Save(this.OutputFileName); } private void AddNodeDocumentation(XElement element, String documentation) { if (String.IsNullOrEmpty(documentation)) return; element.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Documentation").Remove(); element.AddFirst(new XElement("{http://schemas.microsoft.com/ado/2008/09/edm}Documentation", new XElement("{http://schemas.microsoft.com/ado/2008/09/edm}Summary", documentation))); } private String GetTableDocumentation(String tableName) { using (SqlCommand command = new SqlCommand(@" SELECT [value] FROM fn_listextendedproperty ( 'MS_Description', 'schema', 'dbo', 'table', @TableName, null, null)", this._connection)) { command.Parameters.AddWithValue("TableName", tableName); return command.ExecuteScalar() as String; } } private String GetColumnDocumentation(String tableName, String columnName) { using (SqlCommand command = new SqlCommand(@"SELECT [value] FROM fn_listextendedproperty ( 'MS_Description', 'schema', 'dbo', 'table', @TableName, 'column', @columnName)", this._connection)) { command.Parameters.AddWithValue("TableName", tableName); command.Parameters.AddWithValue("ColumnName", columnName); return command.ExecuteScalar() as String; } }
我们的edmx中的代码如下:
<Schema Namespace="yaochufaNewTestModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2008" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl"> <EntityType Name="Activities"> <Key> <PropertyRef Name="ActivityId" /> </Key> <Property Name="ActivityId" Type="int" StoreGeneratedPattern="Identity" Nullable="false" /> <Property Name="ActivityType" Type="int" Nullable="false" /> <Property Name="ProvinceId" Type="int" /> <Property Name="CityId" Type="int" /> <Property Name="Description" Type="nvarchar" MaxLength="50" /> <Property Name="IsActive" Type="bit" Nullable="false" /> <Property Name="EndDate" Type="datetime" /> <Property Name="StartDate" Type="datetime" /> <Property Name="DrawDate" Type="datetime" /> <Property Name="DrawInfo" Type="nvarchar" MaxLength="1000" /> <Property Name="LimitTime" Type="int" /> <Property Name="ShowStartDate" Type="datetime" /> <Property Name="ShowEndDate" Type="datetime" /> <Property Name="PrizeCount" Type="int" /> <Property Name="ModifiedById" Type="int" /> <Property Name="ModifiedByName" Type="nvarchar" MaxLength="50" /> <Property Name="ModifiedDate" Type="datetime" /> <Property Name="CreatedById" Type="int" Nullable="false" /> <Property Name="CreatedByName" Type="nvarchar" MaxLength="50" Nullable="false" /> <Property Name="CreatedDate" Type="datetime" Nullable="false" /> </EntityType>
需要修改的就是EFTSQLDocumentation.Generator源码中的xml命名空间我们要替换成 http://schemas.microsoft.com/ado/2009/11/edm最终在cmd中运行如下代码:
EFTSQLDocumentation.Generator.exe -c "data source=.;initial catalog=yaochufaNewTest;user id=sa;password=123;" -i " D:Feng.TestFeng.TestModel1.edmx"
得到效果图如下: