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

3 篇文章 0 订阅
3 篇文章 0 订阅

目录

初试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
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yangxinyue315

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值