[原创]EF架构随心所欲打造属于你自己的DbModel

前言

我们都知道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}" +
                                  "\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="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.Test\Feng.Test\Model1.edmx"

得到效果图如下:

如果您看完本篇文章感觉不错,请点击左上角的【关注】来支持一下博主,谢谢!

如果您看完本篇文章感觉不错,请点击右下角的 【 推荐 】



作者:枫伶忆

QQ: 616931

出处:http://www.cnblogs.com/fenglingyi

声明:本文版权归作者和博客园共有,未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利


时间: 2024-08-25 16:38:17

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

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

回到目录 之前写过关于实现一个完整的EF架构的文章,文章的阅读量也是满大的,自己很欣慰,但是,那篇文章是我2011年写的,所以,技术有些不成熟,所以今天把我的2014年写的EF底层架构公开一下,这个架构比2011年的有了很大程度的提高,主要在接口规范,查询规范上,并引入了排序功能,两步对完善了EF对数据的批量操作,可以说,这次的架构是很有看点的. 一 一个基础操作接口 /// <summary> /// 基础的数据操作规范 /// 与ORM架构无关 /// </summary> /

EF架构~在Linq to Entity中使用日期函數

回到目录 眾所周知,在linq to entity的查询语句中,不允许出现ef不能识别的关键字,如Trim,Substring,TotalDays等.net里的关键字,在EF查询里都是不被支持的,它的原因可能是为了更好的提高查询的性能吧,毕竟,好的性能取决于你的程序标准,有了一个严格的标准,才能设计出好的程序来. 今天主要说一下,EF为日期方法留的一个后门,<后门>这个词大家在中国社会都应该知道了,顾名思义,就是反着原则走,你的原则对我没有用,哈哈!这东西有时候是有用的,因为在大的原则下,很可

EF架构~过滤导航属性等,拼接SQL字符串

拼接T-SQL串,并使它具有通用性 好处:与服务器建立一次连接,给服务器发一条SQL命令,即可实现 代码如下: 1 /// <summary> 2 /// 构建Insert语句串 3 /// 主键为自增时,如果主键值为0,我们将主键插入到SQL串中 4 /// </summary> 5 /// <typeparam name="TEntity"></typeparam> 6 /// <param name="entity&

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

相关文章系列 第八回 EF架构~将数据库注释添加导入到模型实体类中 第二十一回  EF架构~为EF DbContext生成的实体添加注释(T4模板应用) 第二十二回EF架构~为EF DbContext生成的实体添加注释(T5模板应用) 嗨,没法说,EF4的TT模版加上注释后,升级到EF5的TT模版后,注释就不通用了,所以,还得再研究一下,然后把操作方法再分享出来,没辙的微软! T4模版可能有些凌乱,这在T5模版里有了不错的改进,但我希望解决的问题在T5里并没有得到解决,那就是TT类文件自动得到E

第四十回 EF架构~LinqToEntity里实现left join的一对一与一对多

回到目录 对于linq to sql里实现left join我已经介绍过了,这篇文章的出现是由于最近在项目里遇到的一个问题,解决这个问题花了我不少时间,可能有2个小时,事件是这样的,对于两个表,它们是一对多关系,而需求是返回一个一对一的关系,并将最新的数据返回,这个很多同学都知道,可以使用inner join,但是,对于inner  join来说,当处理的是一对多关系时,它将会出现多条记录,这也是正常的:而它并不满足我们今天的需求,经过测试后,找到了解决这个问题的方法,下面看代码: 一对多关系

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

回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是section数组,这样在修改配置时更加清晰了:而实用性上,彻底改变了读和写不能共用一个仓储对象的缺点,并且在一个事务里可以读写并存,并为了数据的一致性,使事务里的curd操作指向主库,这一点很重要! 前几篇文章的目录 EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服

EF架构为实体模型添加注释

近期做项目,用的是EF的架构,发现自动生成的实体没有注释,所以总结如下方法 1.在edmx中添加注释 1.1类注释 选中实体,打开属性,找到"文档"选项,在"摘要"位置添加类注释,如下图: 1.2属性注释 同类注释,打开属性,找到"文档"选项,在"摘要"位置添加属性注释,如下图: 2.修改tt模版 打开Model.tt文件 2.1添加类注释 找到图中的位置,对t4模板做如下修改 代码复制: string summary=str

EF架构~终于自己架构了一个相对完整的EF方案

EF4.1学了有段时间了,没有静下来好好研究它的架构,今天有空正好把它的架构及数据操作这段拿出来,希望给大家带来帮助,对我自己也是一种总结:P 从图中可以看到,我们用的是MVC3进行程序开发的,哈哈,也是刚开始用3.0,项目整体架构还是传统三层,其它公用层我就不说了,服务层和UI层也不说了,单说EF还在的实体层和数据层,我用EF生成器把它生成后,又整理了一个,因为我不想让EF的低层方法暴露给业务层. 我来一个一个的说我的方案: OAContext.cs:这是生成器生成的,这不作修 Reposit

EF架构~EF异步改造之路~仓储接口的改造~续

回到目录 在写完仓储接口的改造改造后,总觉得有个代码的坏味道,这种味道源于它的DRP,即重复的代码太多了,即异步操作和同步操作其实只是在insert,update和delete上有所不同,获取数据的方法都是一样的,所以,我最后决定,将异步的接口进行改造,让它更加合理,方法后都加上Async的后缀,看上去也更像是个异步方法,呵. 改造后的异步接口 /// <summary> /// 异步操作 /// 基础的数据操作规范 /// 与ORM架构无关 /// </summary> ///