Fork me on GitHub

EF7 Code First Only-所引发的一些“臆想”

At TechEd North America we were excited to announce our plans for EF7, and even demo some very early features. This post will cover the announcements we made during the session. You can also watch the recorded session from TechEd (the EF7 content starts at 46:40). When watching the demos please bear in mind that this is a very early preview - not all the features shown are even submitted into the main code base yet.

以上文字说明来自:EF7 - New Platforms, New Data Stores

没错,微软已经在北美发布了 EF7(应该只是演示、代码甚至都未提交到版本库),时间是 2014-05-19,而我却前几天才看到这篇文章,都过了大半年时间了,哎!

有时候程序员学习新技能,首先了解一下此技能的“性格”和“脾气”,看适不适合自己,就像找对象一样,不适合的话,霸王硬上弓是没用的,那如果合适的话,就好好的了解她、善待她,而不要整天再去想一些其他的(见一个爱一个的不少),“红杏出墙”的最后结果是:到头来什么都没得到。编程语言、编程技术等一些相关的东西,往往是更新速度很快,但也造成了一些“迷惑性”,就像你瞒着女朋友上街看美女一样,守住自己的本心,适合自己,老婆不在多,一个就好。

言归正传,我个人觉得这次 EF7 的发布,就像之前的 ASP.NET vNext 发布一样,是一个里程碑,或者说因为 ASP.NET vNext,所以 Entity Framework 必须要做一些适合“她”的改变,其实追溯到底,他们都是微软下一代 ASP.NET 的组成部分,那 EF7 具体的改变是什么呢?她适不适合你呢?我们先来看一下两个关键词:

  • New Platforms(新平台):之前发布的 ASP.NET vNext,已经支持跨平台了,先试想一样:单独的 Entity Framework 应用程序可以运行吗?或者说 Entity Framework 可以独立存在吗?答案当然是不可以,也就是说 Entity Framework 必须依附于某一类应用程序,比如 Windows Forms、ASP.NET 等,既然 Entity Framework 的“宿主”已经支持跨平台了,那 Entity Framework 就没有不支持的道理,给力的一段话是:EF7 will work on all of these platforms as well as Mono, on both Mac and Linux. 请注意关键字“all”,听起来是蛮激动人心的。
  • New Data Stores(新数据存储):新数据存储是什么?EF7 we will be enabling providers that target non-relational data stores,注意关键字“provider,non-relational”,难道是支持 NoSQL?但文中并没有提到这个关键字,反而提到一个什么 Azure Table Storage?完全没有听说过,这个可以看作是微软给自己打广告,就像针对新平台的视频演示中使用 Windows Phone 一样,见怪不怪了。

因为之前 ASP.NET vNext 的发布,其实这两点内容现在看来 EF7 也“理应如此”,但如果单纯去看 Entity Framework 的发展历程,你会发现这两点改变是非常巨大的,以前的 Entity Framework 只是“循规蹈矩”做好 ORM 份内的工作就好,而这一次完全像脱胎换骨一样,当然有人喜欢,也有人感觉讨厌,除了上面讲到的两个改变关键词,EF7 另一个改变就是:

这篇文章是前几天无意看到的,本来是想翻译一下分享出来的,但奈何英文功力实在太差,翻译到一半就翻译不下去了。Code First 不是我们第一次遇到,从 EF 4.1 版本,Entity Framework 就开始支持 Code First 了,以至于我们在现有 Entity Framework 的最新版本 6. 1 中,可以很好的使用 Code First 模式,当然你也可以使用 Database & Model First 模式,但在 EF7 中,请注意标题的关键字“Only”,也就是说 EF7 将只支持 Code First 模式,这是个什么概念呢?微软到底想干嘛?

别激动,我们先来说下 Code First 的兄长-Database & Model First 模式,这也是我们使用 Entity Framework 的常用模式,我们开发一个应用程序,首先根据业务需求去设计表结构,当然这个工作是业务需求人员和 DBA 去完成的,和程序员相关不大,等数据库表结构什么的确定下来以后,然后我们程序员就开始使用 Entity Framework 根据已有数据库生成对应模型了,大致体现是:

如果在应用程序开发过程中,需求变更了,业务需求人员就会反馈至 DBA,DBA 就会根据业务需求变化修改表结构等,然后就对程序员说:XXX表结构已改。程序员收到数据库修改完成指令后,就开始进行下面操作:

“从数据库生成模型”后,我们针对原来模型写的一些业务方法就必须要做出调整,然后我们就进行重写,重写,再重写。。。

以上是我们使用 Database & Model First 模式的常规开发过程,我相信你肯定深有体会,画了一个简单示意图:

这种模式可以很清楚的看到是以数据库为核心,所有的程序设计、代码编写都是依赖于数据库,数据库一变,那什么都得跟着调整。在这个过程中,Entity Framework 变成了什么?我觉得仅仅是替代我们编写 SQL 代码的工具而已,并没有发挥它的强大之处,ORM 中的 “O”,代表的是 Object(对象),但在这种模式开发的应用中,你会发现这些对象只不过是充满属性集合的类,我们做一些业务简单的应用是可以的,但当开发一些业务极其复杂的应用,按照这种 Database & Model First 模式,大部分的业务都会写在数据库中,比如用存储过程去实现,而对于程序员来说,只需要调用一个数据库接口即可,那还不如直接写 SQL 代码来的方便,以至于 Entity Framework 在这种场景下变成了“鸡肋”,我觉得在 EF7 之前的版本,是微软对开发者做出的一种妥协,就像“从数据库生成模型”这个方式一样,只不过是微软想把你从“事务脚本模式”拉出来,所做出的第一步,之后 EF4.1(开始支持 Code First)是第二步,现在的 EF7(仅支持 Code First)是第三步,这是最重要的一步,也是里程碑的一步,如果在上面应用场景中使用的是 EF7,那将会变成什么呢?请看下面示意图:

你会发现,现在和之前的模式是完全“逆向”的,“Code First Only”模式代表着什么?说白了就是,如果你使用 EF7,那你就必须使用 Code First 模式,不要再想着“从数据库生成模型”了,一切数据库生成操作都必须体现在代码中,这是你的工作,你可能觉得这种思想有点“迎合”领域驱动设计,其实从 EF 4.1 开始使用 Code First,我个人觉得微软已经开始进行改变了,只不过现在改变的更加彻底,至于所蕴含的意义,只能意会了,我现在表达不出来,也许过几年你会发现一切都是理所当然。

如果你使用 Entity Framework,并一直使用的是 Code First 模式,其实 EF7 带给你的变化并不多(除了上面关键字的两点),下面我简单谈一下我自己使用 EF Code First 的一般过程,当然也是我个人非常喜欢的,首先开发一个应用程序,我们一般先设计这个应用程序所存在的模型(Model),这个模型应该不受任何“污染”,也就是说它只是一个单纯的模型,不要在上面加一些配置相关的东西,比如什么 Required、MaxLength 等属性,这个应该是属于数据存储相关的东西,不应该在模型中存在,所以我们应该保持它的“纯净”,然后在模型中专注于业务的实现,这个其实就是领域驱动设计的部分体现,我想这也是以后应用程序开发的最普通过程,当然前提是以后(谁也说不准),贴一下示例模型代码:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Age { get; set; }
    public string Address { get; set; }
    public DateTime DateAdded { get; set; }
    public virtual Role Role { get; set; }
}
public class Role
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateAdded { get; set; }
}

这段代码胡乱摘自之前博文,模型中除了不要放配置相关的东西之外,还有一点就是,在设计对象关联的时候,尽量用对象进行关联,比如 User 中的 Role 属性,如果在之前的设计中,肯定会设计成 RoleId,你如果觉得设计成 Role 对象属性,那数据库中该怎么存储啊?其实如果你有这个想法,那你还是有点受“数据库驱动模式”开发的影响,在模型中应该不要去关注数据存储的一些东西,而应该把设计重点放在业务的实现上,这一点很重要,至于其他你所担心的东西,Entity Framework 都会帮你完成,比如上面模型中,你不需要进行任何配置,使用 EF Code First,他会自动帮你生成相应数据库,User 和 Role 的关联,在数据库中是用 RoleId 表示,但你发现 User 对象中并没有 RoleId,而只有 Role 属性,但当你使用 EF 获取 User 对象,访问其 Role 属性的时候,你可以访问到 Role 对象中的所有属性,也就是说,你在写代码的时候,只需要关注模型的设计即可,其他的你不用关心,一切都有 Entity Framework 呢,至于模型内的一些操作都是对象之间的操作,就像现实生活中我与你对话一般。

另外,还需要提一点是,如果模型对象是多对多关系,比如上面的 User 和 Role,有可能是一个 User 拥有多个 Role,而一个 Role 也可能对应多个 User,那模型该怎么实现呢?其实很简单:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Age { get; set; }
    public string Address { get; set; }
    public DateTime DateAdded { get; set; }
    public virtual IList<Role> Roles { get; set; }
}
public class Role
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateAdded { get; set; }
    public virtual IList<User> Users { get; set; }
}

我们分别给两个对象加了两个集合属性,这也非常符合现实场景,那你所关心的数据库该怎么实现呢?其实你使用 EF Code First 不需要任何配置,它会自动帮你生成三个表:User、Role 和 UserRole,具体关联我就不说了,在对象访问的时候,你会感受不到数据库的“存在”,一切似乎都非常智能,说多了没用,自己体会才是真理。

我喜欢的 Code First 模式是:模型是干净的(不包含任何配置),也更智能化(用对象进行关联),至于数据库映射配置,可以单独去实现,比如上面多对多关联映射的自定义示例代码:

    public class UserRoleDbContext : DbContext
    {
        public UserRoleDbContext()
            : base("name=UserRoleDb")
        {
            //this.Configuration.LazyLoadingEnabled = false;
        }

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

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder
                .Configurations
                .Add(new UserConfiguration())
                .Add(new RoleConfiguration());
            base.OnModelCreating(modelBuilder);
        }

        public class UserConfiguration : EntityTypeConfiguration<User>
        {
            public UserConfiguration()
            {
                HasKey(c => c.Id);
                Property(c => c.Id)
                    .IsRequired()
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
                HasMany(t => t.Roles)
                    .WithMany(t => t.Users)
                    .Map(m =>
                    {
                        m.ToTable("UserRole");
                        m.MapLeftKey("UserId");
                        m.MapRightKey("RoleId");
                    });
            }
        }
        public class RoleConfiguration : EntityTypeConfiguration<Role>
        {
            public RoleConfiguration()
            {
                HasKey(c => c.Id);
                Property(c => c.Id)
                    .IsRequired()
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            }
        }
    }

EF7 符不符合我们的口味?它能给我们带来什么?能改变我们什么?现在说的都是一些“空头支票”,一切只能用时间来证明。

最后分享一个非常棒的文章,也存在我书签很久了,作者是一个 MVP (关键是女的),我觉得她的一些想法和我有一些共鸣,详细内容不说了,大家可以自行体会,关键词:DDD、Entity Framework,文章链接:数据点 - 领域驱动设计的编码:数据聚焦型开发的技巧

posted @ 2014-11-08 22:29  田园里的蟋蟀  阅读(8599)  评论(92编辑  收藏  举报