废话

话说当年,在一个春光明媚的晌午,邂逅了迷人的丁香姑娘,从此拜倒在了她的石榴裙下,至今不能自拔,这位丁香姑娘就是ORM思想。

所谓ORM思想,我的理解就是根据一定的规则,把程序中的对象数据库中的关系数据相互映射转换。在当年之前,我用ADO.NET编写数据持久层,拼接T-Sql语句,这是一个相当繁琐的过程,而且针对不同的数据库,还要调整T-Sql语句。记得,第一个网站上线的时候,数据库改成了MySql的,为了适配MySql,我改了两天的Sql语句。现在每每想起,都不禁摇头哂笑。

ORM思想如何做到屏蔽各大数据库之间的差异呢?程序对象和关系数据之间的相互映射是基于一定的规则的,只要制定好规则,它们的转换就易如反掌。那么,规则怎么制定,谁来制定?规则制定可以简单理解为翻译,即把程序设计语言翻译成数据库语言(T-Sql), 无论什么数据库都兼容最基本的T-Sql语法,外加各自的一些差异。这样不同的程序设计语言就可以针对不同的数据库开发对应的规则。通常数据库厂商或者团队或者社区都会维护这些规则,当然也可以自己DIY。

实现了ORM思想的框架也是琳琅满目,例如:

EntityFramework:.Net程序员最熟悉的啦,由Microsoft支持。

Hibernate:很流行,各种版本的都有。

Dapper:最清凉的,好像就几百K。

And so on……

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及其实现类代码。

public virtual DbSet<MyEntity> MyEntities { get; set; }
public class MyEntity
{
public int Id { get; set; }
public string Name { 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:这个方法是在执行迁移成功之后执行,一般用来初始化数据库用的。例如:我要在生成数据库的时候就初始化一条记录。

protected override void 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()两个方法,分别用于升级和降级。有时候需要我们自己定制它,因此要理解它,可以参考我写的注释。

public partial class InitModel : DbMigration
{
/// <summary>
/// 本次迁移执行的具体操作,即升级数据库。
/// </summary>
public override void 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>
public override void Down()
{
DropTable("dbo.MyEntities");//删除架构为"dbo",表名为”MyEntities"的数据库表。
}
}

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

CREATE TABLE [dbo].[MyEntities] (
[Id] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
CONSTRAINT [PK_dbo.MyEntities] PRIMARY KEY ([Id])
)
CREATE TABLE [dbo].[__MigrationHistory] (
[MigrationId] [nvarchar](150) NOT NULL,
[ContextKey] [nvarchar](300) NOT NULL,
[Model] [varbinary](max) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY ([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", new MySql.Data.Entity.MySqlMigrationSqlGenerator());//设置Sql生成器为Mysql的
}

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

我擦泪!!!

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

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

public class MyEntity
{
public int Id { get; set; }
[MaxLength()]
public string Name { get; set; }
}

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

[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class 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` int not null auto_increment ,`Name` nvarchar() ,primary key ( `Id`) ) engine=InnoDb auto_increment=
create table `__MigrationHistory` (`MigrationId` nvarchar() not null ,`ContextKey` nvarchar() not null ,`Model` longblob not null ,`ProductVersion` nvarchar() not null ,primary key ( `MigrationId`) ) engine=InnoDb auto_increment=
INSERT INTO `__MigrationHistory`(
`MigrationId`,
`ContextKey`,
`Model`,
`ProductVersion`) VALUES (
'201601021247042_InitModel',
'CodeFirstDemo.Migrations.Configuration',
0x1F8B0800000000000400CD57DB6EDB38107D2FD07F20F89C9A4E822EBA81DC22759222D83A09AAB4EFB4347688F2A29254607F5B1FFA49FD851D5A77C9769DECA2280C181639333C73386746FEF9FD47F46EA5247904EB84D1137A3C1A53023A31A9D0CB09CDFDE2D51BFAEEEDCB17D165AA56E44B65771AECD053BB097DF03E3B63CC250FA0B81B299158E3CCC28F12A3184F0D3B198FFF66C7C70C3004C55884449F72ED8582CD033E4E8D4E20F3399733938274E53AEEC49BA8E4862B70194F6042A7687125ACF317A00C25E752700411835C50C2B5369E7B8478F6D941ECADD1CB38C3052EEFD719A0DD824B0725F4B3C6FCD02CC627210BD63856A192DC79A39E18F0F8B4A485F5DD9F452EAD6943E22E9160BF0E596FC89BD0D9BA58A2A47FD8D954DA60D8E37654791C91CEFA515D06582DE183FBB9F4B9858986DC5B2E8FC85D3E9722F907D6F7E62BE889CEA56CA3437CB8D759C0A53B6B32B07EFD091625E6EB9412D6F5637DC7DAADE5536473ADFDE909253778389F4BA82FBF9579EC8D850FA0C1720FE91DF71EAC0E31A0E48AED3D2B7C57A761B5A1662899F1D547D04BFF806A1AA34AAEC40AD26AA544F0590B94183A799B43F79088353737BC4F148AE702E1D6971A5660E5B7DC2A2AA0BC58571ED4CDA5881883EF168800474983A190D6A8A99E6D606B588D7059A1DC4AE16C87C4A319CF32E4AD25F97285C4A5DE5FC54F57832A62B0C46D11458DB63E09AB802FA1B7DB9603F77CCEC3CD4D5335306B2E6107C1D539039EFB0A6868AF5CC2EFC26DBB36FB211AFEAE30258565BCC90E6A2CAD463070DDF45B2EB9DD22A9A991B9D2BB64B9CFBB1049DBBF58194688580F7B9F1F3620A8D71CFA94EFABD5BE497D7A5DB3BDDA8CCA3A79CA8C2A0BA730A104A97914695134F137390AFBA3CDCFA91498706331E35A2CC0F9A281D2D7A3BF7AB3EECF993BCCB9541E387C7EFB101081D45FB6F9C18C38BCEFEB476E93076E879DBF09FA5FDBFCB0111DD4CAD77B1B795193139ACEF135EABE00DA9E01CF6CF4439144ACFDBA175D8013CB264478F9D39084EA6B825636D77A612AEE31BD36A2CAA4773533F03C4596CEAD170B9E78DC4EC0B9CD68FEC2658E26976A0EE9B5BECD7D96FB73E740CD6567B0456CFFF99B69D6C51CDD66E1C9FD1F29204C8129C0AD7E9F0B99D6B8AF86A5B92B442898B2DE1115BE9A60B8E5BA8E7463F481814AFA2E20031DD4720F2A9318CCDDEA983FC273B0E17BC94758F2645DB5BADD417E7D115DDAA30BC197962B57C668FCC35F1816FEC3BCFD175F3BFF74F50C0000,
'6.1.3-40302');
Running Seed method.

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

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

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

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

使用这种姿势遇到了不少坑,都记录到下面这篇博客中。

EF6(CodeFirst)+MySql开发脱坑指南的更多相关文章

  1. EF6(CodeFirst)+MySql开发遇到的坑

    最近一不小心偷个懒就已经过了好几个月了,真是惭愧惭愧,出来混终究是要还的,我还是把”脱坑指南“写完吧,-_-~~.点我打开上篇博客 0x001.架构名”dbo”の殇 坑之首也,当提架构名,在mssql ...

  2. CodeFirst+MySql开发

    CodeFirst+MySql开发简单入门 记录一下使用Mysql进行EF Codefirst方式开发的简单过程. 0.准备工作 安装MySql,mysql-connector-net,mysql-f ...

  3. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  4. Harmony OS 开发避坑指南——源码下载和编译

    Harmony OS 开发避坑指南--源码下载和编译 本文介绍了如何下载鸿蒙系统源码,如何一次性配置可以编译三个目标平台(Hi3516,Hi3518和Hi3861)的编译环境,以及如何将源码编译为三个 ...

  5. Taro 开发踩坑指南 (小程序,H5, RN)

    Taro 开发踩坑指南 (小程序,H5, RN) css taro 如何展示多行文本省略号 https://www.cnblogs.com/xgqfrms/p/12569057.html UI 设计稿 ...

  6. 大数据 SQL Boy 脱坑指南

    不可否认的是 SQL 是一个伟大的发明,它让增删改查的操作更加地便捷化,而且 SQL 的学习成本相对其他编程语言来说较低,被逼到会写 SQL 的运营和产品我都见过不少... 大数据行业跟 SQL 更是 ...

  7. Flutter 开发填坑指南

    引言 第一次在使用Flutter是在Ubuntu机器上,但是因为Android Studio还有Sdk配置问题,flutter doctor总是在这一步报错...最近又在win10上配了一下环境(真香 ...

  8. 微信小程序开发填坑指南V1

    近期用了一星期的时间,开发了一个小程序.小程序名称是:小特Jarvis,取自钢铁侠的管家. 后台采用C#编写,WebAPI接口.其实开发时间并不多,小程序本身提供的API,相比公众号的API来说,已经 ...

  9. Harmony OS 开发避坑指南——DevEco Device Tool 安装配置

    Harmony OS 开发指南--DevEco Device Tool 安装配置 本文介绍如何在Windows主机上安装DevEco Device Tool工具. 坑点总结: 国内部分网络环境下,安装 ...

随机推荐

  1. css例子

    6.背景图像渐变的制作body{ background:#ccc url(xxx.gif)rpeat-x或y:} 7.给一个区块加上背景#branding{ width:700px: height:2 ...

  2. MySQL 5.6 & 5.7最优配置模板

    摘自:http://mp.weixin.qq.com/s?__biz=MjM5MjIxNDA4NA==&mid=207854835&idx=1&sn=c998031ae6816 ...

  3. Beyond Compare 2

    Beyond Compare 2 确实很好用,差异行不交叉,自动留出空白,比windiff要清楚.

  4. jsp jsp指令

    JSP 由HTML和java语句拼接而成的文本,后缀名为.jsp 1.Jsp翻译成servlet:先翻译,Tomcat将翻译后的文件放置在安装目录下(所有JSP页面本质上就是Servlet程序) 2. ...

  5. 史上最强大网盘,网络上的赚钱神器【Yunfile网盘】,注册就送8元

    YunFile.com,是提供在线存储和文件保存服务最大的网站之一,从2007年创立至今,我们提供免费的和您可以承受的收费服务.这些服务包括高级在线存储/远程备份服务,和先进的上传和下载工具.上百万来 ...

  6. 类Arrays

    package p2; import java.util.Arrays; import java.util.List; public class ArraysDemo { public static ...

  7. app启动速度

    跟踪代码发现,应用启动时的白屏会持续到draw调用完成,这个过程中任何耗时操作将导致白屏时间增长. 1.adb shell am start -W -n yourpakagename/MainActi ...

  8. 省市二级联动(原生JS)

    代码如下: <html> <head> <meta charset="UTF-8"> <title>省市二级联动</title ...

  9. n+1 < n , are you sure?

    密码终于找回了,原来是我邮箱把改密链接的邮件当垃圾邮件了-- 回到正题,这是道面试题,原话大致是这样的: n+1<n成立吗?请说明. 当时我听到这个题后直觉是成立的,但是想不到怎么回事,后来别人 ...

  10. [fortify] 变量覆盖漏洞

    一.全局变量覆盖当register_global=ON时,变量来源可能是各个不同的地方,比如页面的表单,Cookie等. <?php echo "Register_globals: & ...