EF CodeFirst 生成mysql表结构

由于项目之前已用sqlServer生成了实体类,用Navicat for mysql 向mysql迁移数据和表结构里失败了,就想通过CodeFirst的方式去生成mysql表。

实验发现,EF CodeFirst模板,运行项目代码时,可以自动向sqlServer创建表结构,但必须先手动去mysql生成表结构,否则报错 NullReferenceException在EntityFramework.dll。

手动根据实体类生成mysql结构步骤


CodeFirst+MySql的正确姿势

如题,本文是使用EntityFramework6框架的感悟(爬坑泪水),以飨同道。

自从学会了EF的基本使用,都是在别人开发好了项目框架上做CRUD,很多细节没有体会到,这次正好有个机会亲自搭建项目框架,深入体会个中奥妙。

配置:win10+vs2015community+.NetFramework4.5.2+MySql5.6

一、基本操作 

1、创建控制台项目:CodeFirstDemo。

2、通过NuGet包管理器安装:EntityFramework6.1.3、MySql.Data.Entity6.9.8 

检查项目的引用中是否有下图所示的四个引用 

添加新建项→ADO.NET实体对象模型(命名MyContext)→空CodeFirst模型。该模型会自动在app.config中添加连接字符串:

<connectionStrings><add name="MyContext" connectionString="data source=(LocalDb)\MSSQLLocalDB;initial catalog=CodeFirstDemo.MyContext;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient"/></connectionStrings>

很显然这是默认的MSSqlServer的配置,稍后再来修改。

3、在MyContext中,反注释掉MyEntities及其实现类代码。

publicvirtualDbSet MyEntities {get;set; }

publicclass MyEntity

    {

        publicintId {get;set; }

        publicstringName {get;set; }

    }

这就是程序中的对象。

根据CodeFirst的约定:Id会被设置为主键。

更多约定详见msdn(https://msdn.microsoft.com/zh-cn/data/jj679962)。

4、如何把MyEntity映射到MySql数据库中?。 三步走:

打开vs工具

第一步: 在控制台中输入Enable-Migrations(启动迁移)。注意:默认项目一定要是模型所在的项目。

此时项目中会自动生成Migration文件夹

下面我来解释下Configuration.cs类

这是迁移的配置类,在最后执行迁移的时候会执行这个类。

它有两个方法:

a、Configuration():无参的构造方法。可以在这里配置迁移之前的操作,后文再详细描述。

b、Seed(MyContext):void:这个方法是在执行迁移成功之后执行,一般用来初始化数据库用的。例如:我要在生成数据库的时候就初始化一条记录。

protectedoverridevoid Seed(CodeFirstDemo.MyContext context)

        {

            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method

            //  to avoid creating duplicate seed data. E.g.

            ////    context.People.AddOrUpdate(

            //      p => p.FullName,

            //      new Person { FullName = "Andrew Peters" },

            //      new Person { FullName = "Brice Lambson" },

            //      new Person { FullName = "Rowan Miller" }

            //    );

            //context.MyEntities.AddOrUpdate(new MyEntity()

            {

                Name ="张三"            });

            context.SaveChanges();

        }

第二步:在控制台输入:Add-Migration InitModel。(InitModel:为本次迁移起个名字)

此时在项目的Migration文件夹中会自动生成迁移记录文件,文件名以“当前时间_本次迁移的名字”作为类名。

记录文件有一个设计类和一个资源类和一个迁移具体操作的方法。

设计类:本次迁移的具体记录。自动生成、维护。

资源类:默认架构和目标。自动生成、维护。

具体操作:该类维护Up()和Down()两个方法,分别用于升级和降级。有时候需要我们自己定制它,因此要理解它,可以参考我写的注释。

publicpartialclass InitModel : DbMigration

    {

        ///<summary>/// 本次迁移执行的具体操作,即升级数据库。

        ///</summary>publicoverridevoid Up()

        {

            //创建架构为"dbo",表名为”MyEntities"的数据库表。            CreateTable(

                "dbo.MyEntities",

                c =>new                    {

                        Id = c.Int(nullable:false, identity:true),//Id,int类型,不可为空,标识列(自动增长)。Name = c.String(),//Name,string类型                    })

                .PrimaryKey(t => t.Id);//设置主键为Id           

        }

        ///<summary>/// 以后如果回滚数据库,那么会执行此降级方法。

        ///</summary>publicoverridevoid Down()

        {

            DropTable("dbo.MyEntities");//删除架构为"dbo",表名为”MyEntities"的数据库表。        }

    }

第三步:在控制台输入Update-DataBase –script。生成Sql脚本。(在迁移过程中出现奇葩问题的时候,就生成sql脚本检查一下吧。)

CREATETABLE[dbo].[MyEntities] (

    [Id][int]NOTNULLIDENTITY,

    [Name][nvarchar](max),

    CONSTRAINT[PK_dbo.MyEntities]PRIMARYKEY([Id])

)CREATETABLE[dbo].[__MigrationHistory] (

    [MigrationId][nvarchar](150)NOTNULL,

    [ContextKey][nvarchar](300)NOTNULL,

    [Model][varbinary](max)NOTNULL,

    [ProductVersion][nvarchar](32)NOTNULL,

    CONSTRAINT[PK_dbo.__MigrationHistory]PRIMARYKEY([MigrationId],[ContextKey])

)INSERT[dbo].[__MigrationHistory]([MigrationId],[ContextKey],[Model],[ProductVersion])VALUES(N'201601021118458_InitModel', N'CodeFirstDemo.Migrations.Configuration',0x1F8B0800000000000400CD57DB6E1B37107D0FD07F20F8D400B6E8CB4B6AAC12B8B25D18896C23EBE49DDA1DC94479D9925C43FB6D79C827F5173AD4DE7725457683A2102068676786670EE70CA9BFBF7D8F3EAC9524CF609D307A4A4F272794804E4C2AF46A4A73BF3C7E473FBCFFE54D749DAA35F95AFB9D073F8CD46E4A9FBCCF2E1873C91328EE264A24D638B3F493C428C653C3CE4E4E7E63A7A70C3005C55C84449F73ED8582CD033ECE8C4E20F3399773938274951DDFC49BACE48E2B70194F604A67E87123ACF357A00C259752700411835C52C2B5369E7B8478F1C541ECADD1AB384303978F4506E8B7E4D24105FDA2753FB48A93B350056B03EB5449EEBC512F4C787A5ED1C286E1AF229736B42171D748B02F42D51BF2A6745E94264A868B5DCCA40D8E036E2775C411E9D98F9A36C06E091F7C9F4B9F5B986AC8BDE5F2883CE40B29928F503C9A3F414F752E65171DE2C3773D039A1EACC9C0FAE2332C2BCCB72925AC1FC786814D5827A6ACE656FBF3334AEE7071BE90D06C7EA7F2D81B0B7F8006CB3DA40FDC7BB03AE4808A2BB677ADF05DAF86DD869AA164CED79F40AFFC1352CED794DC8835A4B5A542F0450B941806799B437F9188B53B37DE4F148AE702E1369B1A2CB0F65B761515506DACAB16EAD752668CC1F71B4480A3A4C5504A6BD276CF36B00DAC56B8AC546EAD70B643E2D19C6719F2D6917C652171A5F7E3F8E56A50650E96B82DA268D0362B6117F0150CDE76E5C03D5FF0B073B3548DDCDA4DD84170BDCE88E7A1025ADAEB90F0BB0CDBAECD618A96BF1B2C49611B6FAA83064B67108C4237F3964B6EB7486A6664AEF42E59EE8B2E45D28D2F2DE30C111B601FF2C346040D86C390F27DBD3A7469566F7A76D09B51D5272F39A3AAC6295D28416A9E451A9A262E9C0735090E93F82F399302EB6D1DE65C8B25385FCE4F8A7DFD6E70D6FD7FCE1DE65C2A0F3C7CFEF3434004567F38E64767C4E1735F3F739B3C71FBABE2EBB7DD4CFF76B68FA7CF41F3BBD83BBDCB469CD2748177A7C7126877F0BF72BA8F9511B1EE1D2FBA0227566D8A70E3D39084966B93D63EB77A696AC2B1BC2EA2DA65B01F73F03C45962EAD174B9E787C9D80739BF3F82B9739BA5CAB05A4B7FA3EF759EE2F9D03B590BDD32C62FBD7DF1C617DCCD17D169EDCCF2801610A2C01EEF5EFB9906983FB66DC8FBB528486A99A1C51E17D04D3AD8A26D39DD10726AAE8BB820C7490C823A84C623277AF63FE0CAFC18697914FB0E249510FB8DD497EBC117DDAA32BC157962B57E568E3C3FF1616FEB8BCFF07A10C3040EA0C0000, N'6.1.3-40302')

如上图所示:第一段创建表MyEntities,是我们的目标,这没错,很正常。

第二段:创建表_MigrationHistory,这是什么鬼。其实这就是EF6框架用来维护模型的表,

[MigrationId]:遍号,主键,存储设计类中Id,其实就是本次迁移记录的名称。

[ContextKey]:标记当前上下文的识别码,主键,因为CodeFirst支持多个上下文实例,所以用这个字段来标记。

[Model]:模型,当前模型的具体描述,加密了。

[ProductVersion]:EF框架的版本号。

EF6框架通过这张表具体记录每次迁移变化,也是通过这张表来检查程序中的对象和数据库中的关系是否一致。

下面继续在控制台输入:Update-DataBase –verbose(或者-v)。更新数据库,并且查看执行的具体sql语句。

结果:

哦,通过查看错误信息,我们可以知道原来是当前配置的是MSSqlServer,而我本机又没有安装MSSqlServer数据库实例,所以当然连接不上了。我们的目标是MySql数据库,所以就要修改App.config中连接字符串了。

打开App.config:

找到连接字符串:

<connectionStrings><add name="MyContext" connectionString="data source=(LocalDb)\MSSQLLocalDB;initial catalog=CodeFirstDemo.MyContext;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient"/></connectionStrings>

修改为MySql的连接字符串:

<connectionStrings><add name="MyContext" connectionString="Data Source=127.0.0.1;port=3306;Initial Catalog=CodeFirstDemoDb;user id=root;password=1234;" providerName="MySql.Data.MySqlClient"/></connectionStrings>

再次在控制台输入:Update-DataBase –verbose。

这是因为当前的Sql生成器依然是MSSqlServer,那么如何启动MySql的Sql生成器呢?

在Migration文件夹中的配置类Congifuration的构造方法中:

public Configuration()

        {

            AutomaticMigrationsEnabled =false;

            SetSqlGenerator("MySql.Data.MySqlClient",newMySql.Data.Entity.MySqlMigrationSqlGenerator());//设置Sql生成器为Mysql的}

再次在控制台输入:Update-DataBase –verbose。

我擦泪!!!

这是MyEntity.Name属性为string类型,直接映射到MySql中的话是longtext,而MySql支持最大长度为767bytes。

可以用DataAnnotations(数据注释)方式,配置MyEntity.Name属性的映射规则:(还有一种方式是FluntApi,之后再介绍)

publicclass MyEntity

    {

        publicintId {get;set; }

        [MaxLength(100)]

        publicstringName {get;set; }

    }

但是到仅仅这样还不够,因为上下文配置还是默认的MSSqlServer的,_MigrationHistory表也有字段是string类型的,还会出现该错误。我们还要在MyContext类上通过特性标记上下文使用MySql的配置。

[DbConfigurationType(typeof(MySqlEFConfiguration))]

    publicclass MyContext : DbContext

    {

    ……

    }

因为修改了模型,所以要重新生成迁移,在控制台输入:Add-Migration InitModel –Force (表示强制执行,即更新。或者简写-f),然后再输入Update-Database –v

PM> add-migration InitModel -f

Re-scaffolding migration'InitModel'.

PM> update-database -v

Using StartUp project 'CodeFirstDemo'.

Using NuGet project 'CodeFirstDemo'.

Specify the '-Verbose' flag to view the SQL statements being applied to the target database.

Target database is: 'CodeFirstDemoDb'(DataSource:127.0.0.1, Provider: MySql.Data.MySqlClient, Origin: Configuration).

Applying explicit migrations: [201601021247042_InitModel].

Applying explicit migration: 201601021247042_InitModel.

create table `MyEntities` (`Id` intnotnullauto_increment ,`Name` nvarchar(100) ,primary key ( `Id`) ) engine=InnoDb auto_increment=0create table `__MigrationHistory` (`MigrationId` nvarchar(150)  notnull,`ContextKey` nvarchar(300)  notnull,`Model` longblob notnull,`ProductVersion` nvarchar(32)  notnull,primary key ( `MigrationId`) ) engine=InnoDb auto_increment=0INSERT INTO `__MigrationHistory`(

`MigrationId`,

`ContextKey`,

`Model`,

......

Running Seed method.

最后执行了Seed方法,我们去检查下MySql数据库,看到如下图所示

最终执行了Seed方法,初始化了这么一条数据。


如此,使用CodeFirst+MySql的基本姿势已经结束了。

以后更新模型的话,只要走第二步和第三步就可以了(或仅第三步)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容