話說當年,在一個春光明媚的晌午,邂逅了迷人的丁香姑娘,今後拜倒在了她的石榴裙下,至今不能自拔,這位丁香姑娘就是ORM思想。html
所謂ORM思想,個人理解就是根據必定的規則,把程序中的對象和數據庫中的關係數據相互映射轉換。在當年以前,我用ADO.NET編寫數據持久層,拼接T-Sql語句,這是一個至關繁瑣的過程,並且針對不一樣的數據庫,還要調整T-Sql語句。記得,第一個網站上線的時候,數據庫改爲了MySql的,爲了適配MySql,我改了兩天的Sql語句。如今往往想起,都不由搖頭哂笑。程序員
ORM思想如何作到屏蔽各大數據庫之間的差別呢?程序對象和關係數據之間的相互映射是基於必定的規則的,只要制定好規則,它們的轉換就易如反掌。那麼,規則怎麼制定,誰來制定?規則制定能夠簡單理解爲翻譯,即把程序設計語言翻譯成數據庫語言(T-Sql), 不管什麼數據庫都兼容最基本的T-Sql語法,外加各自的一些差別。這樣不一樣的程序設計語言就能夠針對不一樣的數據庫開發對應的規則。一般數據庫廠商或者團隊或者社區都會維護這些規則,固然也能夠本身DIY。sql
實現了ORM思想的框架也是琳琅滿目,例如:chrome
EntityFramework:.Net程序員最熟悉的啦,由Microsoft支持。數據庫
Hibernate:很流行,各類版本的都有。架構
Dapper:最清涼的,好像就幾百K。app
And so on……框架
如題,本文是使用EntityFramework6框架的感悟(爬坑淚水),以饗同道。ide
自從學會了EF的基本使用,都是在別人開發好了項目框架上作CRUD,不少細節沒有體會到,此次正好有個機會親自搭建項目框架,深刻體會個中奧妙。工具
配置:win10+vs2015community+.NetFramework4.5.2+MySql5.6
1、基本操做
一、建立控制檯項目:CodeFirstDemo。
二、經過NuGet包管理器安裝:EntityFramework6.1.三、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的配置,稍後再來修改。
三、在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)。
四、如何把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(100)] 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(100) ,primary key ( `Id`) ) engine=InnoDb auto_increment=0 create table `__MigrationHistory` (`MigrationId` nvarchar(150) not null ,`ContextKey` nvarchar(300) not null ,`Model` longblob not null ,`ProductVersion` nvarchar(32) not null ,primary key ( `MigrationId`) ) engine=InnoDb auto_increment=0 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的基本姿式已經結束了。
之後更新模型的話,只要走第二步和第三步就能夠了。