EF6.0 生成的代码中没有注释的解决方法

来源:互联网 发布:单身狗公仔淘宝 编辑:程序博客网 时间:2024/06/08 04:35

目录

      • 目录
  • 初试Entity Framework60
    • 发现问题
      • 先来回顾一下ef40生成的内容
        • ef40 关系元数据不知道大家看不看反正我没仔细看过
        • ef40 Container 声明以
        • ef40 实体集合
        • ef40 AddTo方法
        • ef40 实体声明
        • ef40 实体构造函数
        • ef40 基元属性
      • 再来看EF60生成的内容
        • ef60 构造函数
        • ef60 实体集声明
        • ef60 实体声明
    • 问题解决的必要性
    • 解决问题
      • 第一步 为edmx添加代码生成项也就是EF6x DBContext生成器
      • 第二步 修改T4模板内容
        • ModelContexttt文件
        • Modeltt文件
    • 总结

初试Entity Framework6.0

  之前一直在使用vs2010或者是vs2008,也一直使用的EF4.0一下的版本……在之前,也习惯了Model First的EF设计方式,因为感觉,在设计界面中可以更好的帮助构思;同时,在设计界面中也很容易的增加一些文字说明(这些说明会存在与最终生成的实体类中)。
  

发现问题

  在安装的vs2013之后,我赶紧试了EF6.0……此处省略好几万字。
  打开了一个以前设计并完成的项目,当中包含了edmx文件,我想看看ef6.0生成的代码到底和ef4.0有什么不同。
  结果发现:ef6.0(T4模板)生成的cs文件中,竟然没有包含注释(edmx中的文档),这个让我情何以堪啊。

先来回顾一下ef4.0生成的内容

ef4.0 关系元数据(不知道大家看不看,反正我没仔细看过)

#region EDM 关系源元数据[assembly: EdmRelationshipAttribute("Models", "HospitalProject", "Hospital", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(HNWMS.EFData.Hospital), "Project", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(HNWMS.EFData.Project))]///... ...[assembly: EdmRelationshipAttribute("Models", "UserMyDisk", "User", System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(HNWMS.EFData.User), "MyDisk", System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(HNWMS.EFData.MyDisk))]#endregion

ef4.0 Container 声明以

  ef4.0中Container继承自ObjectContext
  构造函数(默认生成的)有三个。

    /// <summary>    /// 没有元数据文档可用。    /// </summary>    public partial class Container : ObjectContext

ef4.0 实体集合

  有公共的带有get访问器的属性,也有对应的私有字段。完全面向对象的写法;唯一不好的就是,没有自动生成实体集合的注释内容(summary)。

        /// <summary>        /// 没有元数据文档可用。        /// </summary>        public ObjectSet<User> Users        {            get            {                if ((_Users == null))                {                    _Users = base.CreateObjectSet<User>("Users");                }                return _Users;            }        }        private ObjectSet<User> _Users;

ef4.0 AddTo方法

  虽然表明了“已弃用”,但是,在其他地方调用的时候还是很方便,起码很直接。

        /// <summary>        /// 用于向 Users EntitySet 添加新对象的方法,已弃用。请考虑改用关联的 ObjectSet&lt;T&gt; 属性的 .Add 方法。        /// </summary>        public void AddToUsers(User user)        {            base.AddObject("Users", user);        }

ef4.0 实体声明

  加入了很多Attribute的声明,说实在的,我从来没有注意过这些东西,也不知道做什么用的。

    /// <summary>    /// 用户基类(同时描述总部人员)    /// </summary>    [EdmEntityTypeAttribute(NamespaceName="Models", Name="User")]    [Serializable()]    [DataContractAttribute(IsReference=true)]    [KnownTypeAttribute(typeof(ProjectManager))]    [KnownTypeAttribute(typeof(HospitalServicer))]    [KnownTypeAttribute(typeof(NursingWorker))]    public partial class User : EntityObject

ef4.0 实体构造函数

  庞大到不敢看,参数是所有属性的排列,然后加上了个global::用以排除类型冲突;在开发的过程中,我似乎没有使用过实体构造函数来构造实体的实例。

public static User CreateUser(global::System.String code, global::System.String loginPassword, global::System.String realName, global::System.String mobilePhoneNO, global::System.String xType, global::System.String iDCordNO)

ef4.0 基元属性

  同实体集合一般,完全符合面向对象的写法,有属性,就有对应的字段存在。另外再set访问器中还显示的触发了“自跟踪实体”的四个事件(具体什么是自跟踪实体,这里不做复述。)

        /// <summary>        /// 用户编码        /// </summary>        /// <LongDescription>        /// 编码规则:&#xA;U开头+4位数字顺序码&#xA;若4位顺序码达到9999则为&#xA;UA开头+3为数字顺序码&#xA;以此类推&#xA;        /// </LongDescription>        [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]        [DataMemberAttribute()]        public global::System.String Code        {            get            {                return _Code;            }            set            {                if (_Code != value)                {                    OnCodeChanging(value);                     ReportPropertyChanging("Code");                    _Code = StructuralObject.SetValidValue(value, false);                    ReportPropertyChanged("Code");                    OnCodeChanged();                }            }        }        private global::System.String _Code;

  虽然,我在上边的描述中说了提到了很多关于ef4.0中的“不好”,但是这并不表示我不认同ef4.0。下面说几点我理解的ef的好处:

  • 我还是很喜欢ef的,因为其简单、易用,配合上mvc、WCF Data Service很容易就完成一个解决方案;
  • 我更加喜欢vs提供的edmx设计器,在这里我可以不借助其他“构思辅助”软件,就可以完成“数据设计”以及“数据关系”的梳理工作。
  • 通过edmx我可以很容易的为“实体”“属性”“导航属性”添加“文档”(在最终的代码中为summary,这也是我写这篇文章的目的。)
  • 因为解决方案中存在有一个edmx文件,在其他人接手改解决方案时,很容易就可以看到数据设计,很容易就可以理解数据关系。

      所以,在大家都在“喊叫”EF code first的时候,我仍然使用着model or db first。所谓“仁者见仁智者见智,萝卜白菜各有所爱”,大牛们别喷我。谢谢^_&.

再来看EF6.0生成的内容

ef6.0 构造函数

  不同于EF4.0,在生成的Container上方,并没有出现很多的“元数据”内容。打开这个类的时候,给我的第一感觉就是,啊!好简单啊。
  Container继承自DBContext,至于与ObjectContext有什么不同,请大家找度娘或者MSDN。

    public partial class Container : DbContext

ef6.0 实体集声明

  与ef4.0首先不同在,实体集不再是ObjectSet类型的了,而是DBSet类型的了;其次,它简化了get和set访问器(同时少了对应字段的声明,到时符合了隐式属性访问器的声明方法)
  不好再那里呢???注释那里去了,ef4.0最起码还有个 “没有元数据文档可用。”的注释。

public virtual DbSet<User> Users { get; set; }

ef6.0 实体声明

  与ef4.0不同在,实体的构造函数不再那么臃肿,无参数,在内部也仅仅是为导航属性赋予了初始值;同时,属性的get和set也简化了,乍一看,这样一个类好像是谁写出来的Demo呢。
  不过,与实体集声明 一般,注释那里去了,ef4.0中,可是把edmx中的“文档以及长说明”都生成在了summary中的。

    public partial class User    {        public User()        {            this.SignIns = new HashSet<SignIn>();            this.MyMenus = new HashSet<MyMenu>();            this.MyDisks = new HashSet<MyDisk>();        }        public string Code { get; set; }        public string LoginPassword { get; set; }        public string RealName { get; set; }        public string MobilePhoneNO { get; set; }        public string xType { get; set; }        public string IDCordNO { get; set; }        public virtual ICollection<SignIn> SignIns { get; set; }        public virtual ICollection<MyMenu> MyMenus { get; set; }        public virtual ICollection<MyDisk> MyDisks { get; set; }    }

  上面非常简单的和肤浅的叙述了ef4.0和ef6.0之间的区别,并阐述了我个人的好恶。

问题解决的必要性

  看到这里,很多大牛可能会说“老弟,out man,大家现在都在2015,你还2013呢??”“不就是一个注释么?有那个必要么?”
  小弟我解释一下,呵呵,有几年了,没有工作在第一线,没有进行过code的工作,所以对于vs和其他编辑器等,都不甚熟悉了……注释可是很重要的,尤其是符合vs要求的/// summary 注释,因为vs有智能提示啊,我想大家都见过也用过,当.的时候,就会出现很多该类型下的属性啊,方法啊…….拜托都是英文,如何分辨?就算你E文好,请问,你一个人开发应用系统的?
  呵呵,有点强词夺理了。
  总之,我要大吼一声“我要注释!不管是我写的代码的注释,还是生成的代码的注释,我都要!还要看的懂得注释。”
  悄悄的告诉一些比我还菜的小鸟们,其实vs中代码的(符合规范的)注释,相当有用的,比如开发完成后,你可以通过注释生成chm类型或者help view2.x类型的帮助文件的(这里不多说)。

解决问题

第一步 为edmx添加“代码生成项”也就是“EF6.x DBContext生成器”

步骤:

  1. 在vs中打开edmx
  2. 随便找个空白的地方右键,然后选择“添加代码生成项”
  3. 然后在随后出现的窗口中选择“EF6.x DBContext生成器”,确定
  4. 验证:在解决方案资源管理器中,edmx文件下方就会出现你刚刚添加的“代码生成内容”,一般叫做Model.Context.tt 和Model.tt(其实这两个东西,就是T4模板;打开它,然后按“ctrl+s”的时候,它就会自动执行,并按照edmx文件中的设计,生成相关的Container 、DBSet、entity)

第二步 修改T4模板内容

Model.Context.tt文件

找到内容:

    public string DbSet(EntitySet entitySet,System.Collections.Generic.IEnumerable<System.Data.Entity.Core.Metadata.Edm.GlobalItem> itemCollection)    {        return string.Format(            CultureInfo.InvariantCulture,            "{0} virtual DbSet<{1}> {2} {{ get; set; }}",            Accessibility.ForReadOnlyProperty(entitySet),            _typeMapper.GetTypeName(entitySet.ElementType),            _code.Escape(entitySet), summary);    }

这个方法是干什么的呢?其实就是返回一段类似下发代码的文本

public virtual DbSet<User> Users { get; set; }

更改成为:

    public string DbSet(EntitySet entitySet,System.Collections.Generic.IEnumerable<System.Data.Entity.Core.Metadata.Edm.GlobalItem> itemCollection)    {    string summary = entitySet.ElementType.Documentation == null ? "(error message:not have summary in edmx.)" : entitySet.ElementType.Documentation.Summary;        return string.Format(            CultureInfo.InvariantCulture,            "/// <summary>\r\n\t/// {3}的集合\r\n\t/// </summary>\r\n\t{0} virtual DbSet<{1}> {2} {{ get; set; }}",            Accessibility.ForReadOnlyProperty(entitySet),            _typeMapper.GetTypeName(entitySet.ElementType),            _code.Escape(entitySet), summary);    }

呵呵,你可能觉得,我写的Format中,不该美观。。。。。。我的解释是,反正这个T4最终不会被编译到程序集中,无所谓啦。
这样,最终产生的内容就类似与:

/// <summary>/// 用户基类(同时描述总部人员)的集合/// </summary>public virtual DbSet<User> Users { get; set; }

Model.tt文件

找到内容:

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)){    fileManager.StartNewFile(entity.Name + ".cs");    BeginNamespace(code);#>

这段代码,就是根据实体的类型名称,产生一个独立的cs文件,并产生Namespace声明,若为类型添加注释,不就是在Namespace下边么……
更改成为:

string summary=string.Empty;foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)){    fileManager.StartNewFile(entity.Name + ".cs");    BeginNamespace(code);    summary = entity.Documentation == null ? entity.Name : entity.Documentation.Summary;#>/// <summary>/// <#=summary#>/// </summary> 

还没有完成,继续,找到

    public string Property(EdmProperty edmProperty)    {        return string.Format(CultureInfo.InvariantCulture,            "{0} {1} {2} {{ {3}get; {4}set; }}",            Accessibility.ForProperty(edmProperty),            _typeMapper.GetTypeName(edmProperty.TypeUsage),            _code.Escape(edmProperty),            _code.SpaceAfter(Accessibility.ForGetter(edmProperty)),            _code.SpaceAfter(Accessibility.ForSetter(edmProperty)));    }    public string NavigationProperty(NavigationProperty navProp)    {        var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType());        return string.Format(            CultureInfo.InvariantCulture,            "{0} {1} {2} {{ {3}get; {4}set; }}",            AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)),            navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,            _code.Escape(navProp),            _code.SpaceAfter(Accessibility.ForGetter(navProp)),            _code.SpaceAfter(Accessibility.ForSetter(navProp)));    }

更改为:

    public string Property(EdmProperty edmProperty)    {        return string.Format(CultureInfo.InvariantCulture,            "/// <summary>\r\n\t/// {5}\r\n\t/// </summary>\r\n\t{0} {1} {2} {{ {3}get; {4}set; }}",            Accessibility.ForProperty(edmProperty),            _typeMapper.GetTypeName(edmProperty.TypeUsage),            _code.Escape(edmProperty),            _code.SpaceAfter(Accessibility.ForGetter(edmProperty)),            _code.SpaceAfter(Accessibility.ForSetter(edmProperty)),            edmProperty.Documentation == null ? "" : edmProperty.Documentation.Summary            );    }    public string NavigationProperty(NavigationProperty navProp)    {        var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType());        return string.Format(            CultureInfo.InvariantCulture,            "/// <summary>\r\n\t/// {5}\r\n\t/// </summary>\r\n\t{0} {1} {2} {{ {3}get; {4}set; }}",            AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)),            navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,            _code.Escape(navProp),            _code.SpaceAfter(Accessibility.ForGetter(navProp)),            _code.SpaceAfter(Accessibility.ForSetter(navProp)),            navProp.Documentation == null ? "" : navProp.Documentation.Summary            );    }

然后“保存”,产生的cs文件中就类似与下边了:

    /// <summary>    /// 用户基类(同时描述总部人员)    /// </summary>    public partial class User    {    ......        /// <summary>        /// 用户编码        /// </summary>        public string Code { get; set; }    ......    }

  OK!这样就搞定了edmx生成内容中无注释的问题了。
  再次大吼“注释有用!”

总结

  总之,我个人觉得,在使用一个(别人能够归纳与一个系列的)新东西的时候,一定要从设计者的角度去考虑,每一样东西都是有用的。

0 0
原创粉丝点击