前言

我们都知道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 = ;
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 = ;
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}" +
"\n => 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="" 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="" />
<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="" />
<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="" />
<Property Name="ModifiedDate" Type="datetime" />
<Property Name="CreatedById" Type="int" Nullable="false" />
<Property Name="CreatedByName" Type="nvarchar" MaxLength="" 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.Test\Feng.Test\Model1.edmx"

得到效果图如下:

[原创]EF架构随心所欲打造属于你自己的DbModel的更多相关文章

  1. EF架构随心所欲打造属于你自己的DbModel【转】

    前言 我们都知道EF可以生成Dbmodel,系统生成的Model有时候并不是我们想要的,如何我们要生成自己的Model,那么久需要我们手动的去修改T4模版,T4是对“Text Template Tra ...

  2. EF架构~为EF DbContext生成的实体添加注释(T5模板应用)

    回到目录 相关文章系列 第八回 EF架构~将数据库注释添加导入到模型实体类中 第二十一回  EF架构~为EF DbContext生成的实体添加注释(T4模板应用) 第二十二回EF架构~为EF DbCo ...

  3. EF架构~数据分批批量提交

    回到目录 对于大数据量提交,包括插入,更新和删除,我始终不建议用EF自带的方法,因为它会增加与数据库的交互次数,一般地,EF的一个上下文在提交时会打开一个数据连接,然后把转换成的SQL语句一条一条的发 ...

  4. EF架构~基于EF数据层的实现

    回到目录 之前写过关于实现一个完整的EF架构的文章,文章的阅读量也是满大的,自己很欣慰,但是,那篇文章是我2011年写的,所以,技术有些不成熟,所以今天把我的2014年写的EF底层架构公开一下,这个架 ...

  5. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一

    回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是sect ...

  6. EF架构~扩展一个分页处理大数据的方法

    回到目录 最近总遇到大数据的问题,一次性处理几千万数据不实际,所以,我们需要对大数据进行分块处理,或者叫分页处理,我在EF架构里曾经写过类似的,那是在进行BulkInsert时,对大数据批量插入时候用 ...

  7. EF架构~CodeFirst数据迁移与防数据库删除

    回到目录 本文介绍两个概念,防数据库自动删除,这是由于在code first模式下,当数据实体发生变化时,会对原来数据库进行删除,并将新数据表添加进来,但这对于我们的运营环境数据库,是万万不能接受的, ...

  8. EF架构~CodeFirst生产环境的Migrations

    回到目录 Migrations即迁移,它是EF的code first模式出现的产物,它意思是说,将代码的变化反映到数据库上,这种反映有两种环境,一是本地开发环境,别一种是服务器的生产环境,本地开发环境 ...

  9. EF架构~为EF DbContext生成的实体添加注释(T5模板应用)(转载)

    转载地址:http://www.newlifex.com/showtopic-1072.aspx 最近新项目要用Entity Framework 6.x,但是我发现从数据库生成模型时没有生成字段的注释 ...

随机推荐

  1. ASP.NET批量下载文件的方法

    一.实现步骤 在用户操作界面,由用户选择需要下载的文件,系统根据所选文件,在服务器上创建用于存储所选文件的临时文件夹,将所选文件拷贝至临时文件夹.然后调用 RAR程序,对临时文件夹进行压缩,然后输出到 ...

  2. npp 文本编辑器 开源

    下载地址 https://notepad-plus-plus.org/download/v6.8.4.html

  3. 20145232 韩文浩 《Java程序设计》第9周学习总结

    教材学习内容总结 学习目标 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义泛型和自定义枚举 会使用标准注解 JDBC标准主要分为两个部分:JDBC应用程序开发者接口和 ...

  4. 20169207 《Linux内核原理与分析》第十一周作业

    阅读学习教材「Linux内核设计与实现 (Linux Kernel Development)」第教材第17,19,20章. 在第17章设备与模块章节,关于设备驱动和设备管理,我们讨论四中内核成分. 1 ...

  5. 基于SVG+AJAX的网页数据监控

    这个是前一阵做的一个火灾报警主机数据网页监控,前后台主要耗时5小时.绘图2小时,配置后端采集端1小时,测试2小时. 用的SVG,上面画的指示灯可以实时显示传感器的状态. 用开源方案实现. 如果集成到自 ...

  6. Spring的两种代理JDK和CGLIB的区别浅谈

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  7. android 线程中断的处理

    android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@4 ...

  8. STL其他--<tuple>用法【C11】

     tuple 库 tuple 库 是能够将不同类型的对象组合起来形成一个对象.和pair 对象一样,但是可以组织多种不同类型的元素. tuple中的元素类型是在编译时期决定的.与<utility ...

  9. 关于建立MySQL数据库,中文出现乱码问题

    MySQL的ini文件中的默认编码设置utf-8不用改 loose-default-character-set = utf-8 注意:需要改动部分 1.如图所示 建立schema时改变字符编码 改变为 ...

  10. kafka groupid

    kafka 分组 简言之,就是相同分组的消费者,会分摊消费kafka中同一个topic中的数据.