• 初识Entity Framework CodeFirst(2)


    上一回合,我们讨论了如何简单的使用Entity Framework CodeFirst功能。

    结尾的时候,我们提出了一个有趣的问题,如果我们的数据实体需要发生变化呢?需要添加多一个Model类呢?修改已有实体中字段呢?我们该怎么办?该不会是把数据库删掉,然后让程序重新生成吧?很明显,答案当然不是啦。EF作为微软推荐的框架之一,没有这么差劲的。

    本节,我们讨论一下内容:

    1、Migration控制台

    2、修改已有实体,添加/删除 数据库字段

    3、添加新实体模型与数据库表映射

    4、修改实体属性与数据库字段名映射

    代码点击这里下载


    1、打开程序包管理器控制台,并启动Migrations (迁移)

    方法如下:点击工具->库程序包管理器->程序包管理器控制台

    在控制台中输入“Enable-Migrations” (小技巧:这里支持Tab自动补全),启动Migrations。

    这时候,项目解决方案处会多出一个文件夹“Migrations”以及其下级的文件

    “Configuration.cs”文件包含本项目CodeFirst的基本配置,一般情况下我们大可不必修改里面的内容。

    201303241026370_InitialCreate
    public partial class InitialCreate : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Blogs",
                    c => new
                        {
                            BlogID = c.Int(nullable: false, identity: true),
                            BlogName = c.String(),
                        })
                    .PrimaryKey(t => t.BlogID);
                
                CreateTable(
                    "dbo.Posts",
                    c => new
                        {
                            PostID = c.Int(nullable: false, identity: true),
                            Title = c.String(),
                            Content = c.String(),
                            BlogID = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.PostID)
                    .ForeignKey("dbo.Blogs", t => t.BlogID, cascadeDelete: true)
                    .Index(t => t.BlogID);
                
            }
            
            public override void Down()
            {
                DropIndex("dbo.Posts", new[] { "BlogID" });
                DropForeignKey("dbo.Posts", "BlogID", "dbo.Blogs");
                DropTable("dbo.Posts");
                DropTable("dbo.Blogs");
            }
        }

    “201303241026370_InitialCreate.cs”(命名有系统自动生成)包含的则是初始化语句。大家可以看到里面包含了两个方法,一个是Up,用于初始化时建立数据库(表);另外一个则是Down,删除数据库(表)的。

    我们必须借助Migrations 来对实体类中的修改更新到数据库的结构当中。

    2、如何修改已有实体(实例:在已有model中添加一个字段)

    举个例子(还是来自于MSDN),我们对Blog Model进行修改,添加一个“Url”的字段

    class Blog
        {
            public int BlogID { get; set; }
            public string BlogName { get; set; }
            public string Url { get; set; }
        }

    打开Migration控制台,输入“Add-Migration AddUrl”,这时我们发现解决方案中多了一个文件,名为:201303241155123_AddUrl

    该文件产生的代码如下:

    AddUrl
        public partial class AddUrl : DbMigration
        {
            public override void Up()
            {
                AddColumn("dbo.Blogs", "Url", c => c.String());
            }
            
            public override void Down()
            {
                DropColumn("dbo.Blogs", "Url");
            }
        }

    再在Migration控制台输入:“Update-Database”,更新数据库结构。

    新增的字段就乖乖的新建出来了。

    这里解析一下:

      (1)、Migration控制台中,“Add-Migration XXX”,其中的XXX为各位读者自己命名,可以起任意的名字,这里还是建议各位读者朋友名一个有实意的名字以方便后续的工作。

      (2)、生成的新代码中,它继承自DbMigration,里面包含了两个重写方法,UP和Down,Up中调用了AddColumn方法插入新字段,传入三个参数,分别是“表名”、“字段名”以及一个用于确定数据类型的lambda表达式;Drow方法则调用DropColumn,传入“表名”和“字段名”来删除该字段。有兴趣的同学可以对DbMigration进行反编译,可以看到里面包含的所有方法。

    3、新增一个实体(实例:添加一个Type Model和一个User Model)

    3.1、添加一个Type实体

    class Type
        {
            public int TypeID { get; set; }
            public string TypeName { get; set; }
        }

    修改上下文BlogContext,添加一个Types属性

        class BlogContext:DbContext
        {
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
            public DbSet<Type> Types { get; set; }
        }

    调出Migration控制台,“Add-Migration AddType”——>“Update-Database” ,很好,Type表已经轻松的生成。

    3.2、添加一个User Model

    各位读者有没有发现,之前我们一直新建的实体,实体字段第一位都是XXID(总是int类型),这里我们做一点改动,不要XXID,只要UserName和DisplayName两个string类型的字段。

    添加Model

    class User
        {
            public string UserName { get; set; }
            public string DisplayName { get; set; }
        }

    修改上下文

    class BlogContext:DbContext
        {
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
            public DbSet<Type> Types { get; set; }
            public DbSet<User> Users { get; set; }
        }

    我们还像以往一样,调出Migration控制台,然后执行“Add-Migration AddUser”——>“Update-Database”

    聪明的读者一定会猜得出后果会怎么样,没错,这回报错了,报错内容为:没有找到主键

    这时,我们需要在User中手动添加一个主键的标签

     class User
        {
            [System.ComponentModel.DataAnnotations.Key]
            public string UserName { get; set; }
            public string DisplayName { get; set; }
        }

    重新调出Migration控制台,“Add-Migration AddUser”——>“Update-Database”

    通过,User表已经生成在数据库中。

    这时,我们或许会产生或多或少的暗示——不指定主键的时候,EF默认会自动的帮我们指定。

    这里,我把Type实体和User实体通过调用Migration生成的两个Add文件的代码贴出来。

    AddType
    public partial class AddType : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Types",
                    c => new
                        {
                            TypeID = c.Int(nullable: false, identity: true),
                            TypeName = c.String(),
                        })
                    .PrimaryKey(t => t.TypeID);
                
            }
            
            public override void Down()
            {
                DropTable("dbo.Types");
            }
        }
    AddUser
    public partial class AddUser : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Users",
                    c => new
                        {
                            UserName = c.String(nullable: false, maxLength: 128),
                            DisplayName = c.String(),
                        })
                    .PrimaryKey(t => t.UserName);
                
            }
            
            public override void Down()
            {
                DropTable("dbo.Users");
            }
        }

    对比一下,答案也许各位读者已经找到了。没错,答案就在重写的UP中,各位是否发现,没有指明主键的Type实体中,EF会自动的把第一个字段指定为identity(自增)的int型主键,当然,前提必须为这个被指定的字段在model中的属性为int类型。而在User实体中,全部都是string类型的属性,因为EF无法通过默认的方式找到可以自动添加的主键字段,所以Migrants控制台想Add-Migrants时就会发生内容为:找不到主键的报错啦。

    这里我需要补充一下,精明的读者也许发现,通过CodeFirst生成的数据表中,字段的类型也只能确定个大概,并不能进行比较精确的确定,比如通过string类型属性反向生成的字段,其字段容量大小竟然为“Max”;其实,在“Update-Database”之前,我们可以通过对“Add-Migration”中生成的Add文件(暂时想不出有什么方法形容这些文件)中的UP方法进行细小的微调,然后再执行“Update-Database”,我们就可以生成真正想要字段大小啦。

    3、修改已存在的实体,数据库中对应字段的字段名

    有时候,我们已经使用EF CodeFirst对数据库已经进行了反向的生成,但是,我们又想修改一下数据库中,与实体属性对应的某个字段的字段名,这个时候我们应该怎么办呢?

    这里,我们只需要在上下文中override一个方法

    class BlogContext:DbContext
        {
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
            public DbSet<Type> Types { get; set; }
            public DbSet<User> Users { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<User>()
                    .Property(u => u.DisplayName)
                    .HasColumnName("Display_Name");
            }
        }

    在Migration中,“Add-Migration”——>“Update-Migration”

    好的,O了。


    这节我们已经讨论完毕了,各位读者如果有什么更好的建议或者意见,欢迎留言。

  • 相关阅读:
    BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第13章节--使用业务连接服务创建业务线解决方式 创建启用BCS的业务解决方式
    POI 导入excel数据自己主动封装成model对象--代码分析
    四旋翼飞行器Quadrotor飞控之 PID调节(參考APM程序)
    Detours改动段属性漏洞
    C++中父类的虚函数必需要实现吗?
    深入理解JavaScript系列(12):变量对象(Variable Object)
    CSS 类、伪类和伪元素差别具体解释
    Qt Quick 之 PathView 具体解释
    读《一年一度屈原祭,端午时节话公知》有感
    Volley简单学习使用五—— 源代码分析三
  • 原文地址:https://www.cnblogs.com/xiaodiejinghong/p/2979924.html
Copyright © 2020-2023  润新知