對於SQL Server、MySql、Oracle等這些傳統的數據庫,基本都是關系型數據庫,都是體現實體與實體之間的聯系,在以前開發時,可能先根據需求設計數據庫,然后在寫Model和業務邏輯,對於Model類基本都是和表的字段對應着,而表中存的每條記錄又和類的實例對象對應着,有了這個對照關系,就是能不能只在一邊設計,在數據庫設計表或在VS中設計Model,然后直接生成另一邊,這樣就省了好多時間成本。於是有了ORM,Object Relation Mapping,對象關系映射。既然可以根據Model可以生成數據庫,數據庫也可以生成Model,Model、數據庫又是分離的,我們也可以根據Model生成不同類型(Sql Server\Oracle)數據庫,而不同類型的數據庫(Sql Server\Oracle)也可以生成同樣的Model,而它們共同的紐帶就是Mapping。
EF實體框架有3種類型,Data First、Model First、Code First。從今天起,將來的幾篇博客可能都是關於Code First的,可能有人會問,其他的呢?對於另外兩個我不打算花太多的時間,現在code first用的比較多,而且和其他兩個比來說更加方便簡單,code first沒有包含CSDL(Conceptual Schema Definition Language 概念架構定義語言)、SSDL(Store Schema Definition Language存儲架構定義語言)、MSL(Mapping Specification Language 映射規范語言)的映射定義,可是使用基於約定的映射。例如主鍵,只需要用Id命名屬性或以Id結尾,這種會自動映射到主鍵上。對於上面的CSDL、SSDL、MSL根據中文應該也能猜出一二來,其實CSDL概念架構定義語言,定義概念的嘛,當然是定義.Net類的,而SSDL存儲架構定義,既然是存儲,肯定是數據庫啊,所以它是描述表及其關系的結構。而MSL映射規范語言,當然是用來映射的,比如類中的Name屬性可能在數據庫定義的列名不是name,那怎么辦呢?這時有了MSL就好辦了,它就是用來描述映射關系的。
上面瞎逼逼半天,實際上今天是想大致演示下code first的用法,做簡單的增刪改查。
一、Model
首先是創建了一個控制台應用程序EFCodeFirstDemo,又創建了一個存放Model的類庫EFCodeFirstModels,以及一個與數據庫有關系的類庫EFCodeFirstDataAccess,算是三層架構中的DAL,至於BLL先不創建,只是簡單的演示。既然是code first,管理對象,那肯定要先有一個Model類,這里在EFCodeFirstDemo中定義了一個Student類。在Student類中使用約定定義StuId為主鍵,由於默認會把Id結尾的屬性作為主鍵,所以不用特性也可以。
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFCodeFirstModels { public class Student { [Key] public string StuId { get; set; } public string Name { get; set; } public int Age { get; set; } public Student(string stuId, string name, int age) { this.StuId = stuId; this.Name = name; this.Age = age; } //定義無參數的構造函數主要是因為在通過DbSet獲取對象進行linq查詢時會報錯 //The class 'EFCodeFirstModels.Student' has no parameterless constructor. public Student() { } } }
二、DbContext數據庫上下文
DbContext數據庫上下文,定義了從實體對象到數據庫的映射,從數據庫中檢索數據,就要使用它。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.Entity; using EFCodeFirstModels; using System.Configuration; namespace EFCodeFirstDataAccess { public class EFCodeFirstDbContext:DbContext { public EFCodeFirstDbContext():base("name=MyStrConn") { } public DbSet<Student> Students { get; set; } } }
在使用DbContext時要先通過NuGet添加EntityFramework,在類中引入System.Data.Entity,像上面的代碼中我們給DbContext指定了數據庫連接字符串,名字是MyStrConn,我們可以看下DbContext類的構造函數.

上面提供了幾種構造函數,今天主要看下第一個傳nameOrConnectionString和無參數的。如果不傳參數,它會自定將數據庫的名字命名為類庫名.類名,像上面的如果不使用無參數的構造函數會創建一個名為EFCodeFirstDataAccess.EFCodeFirstDbContext的數據庫。而我們的demo中是使用了參數的,參數的名是nameorConnectionString,注意是or那意味着有兩種情況,一種是name,一種是ConnectionString,在上面的參數是"name=XXX",這種是ConnectionString,既然是ConnectionString,那肯定有連接字符串,在哪呢?我開始是寫在了EFCodeFirstDataAccess類庫中,可以始終報錯,報初始化的錯誤,正確的是寫在控制台應用程序中的配置文件中,在配置文件App.config中添加結點。這里也要注意是要提供providerName,而且configSections必須是configuration的第一個結點,我剛才把connectionStrings添加到第一個也是提示錯誤。
<connectionStrings>
<add name="MyStrConn" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=CodeFirstDb;Integrated Security=True"/>
</connectionStrings>
我們也可以不使用ConnectionString,而是直接復制數據庫名,它會先找配置文件對於的連接字符串,如果未找到,則以它自己命名。
三、簡單操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EFCodeFirstModels; using EFCodeFirstDataAccess; namespace EFCodeFirstDemo { class Program { static void Main(string[] args) { //using能及時釋放資源,例如數據庫連接異常,可以即使將上下文釋放 using (var db=new EFCodeFirstDbContext()) { Student stu = new Student("0001", "cuiyanwei", 25); db.Students.Add(stu); db.SaveChanges(); string name= db.Students.Select(p => p.Name).FirstOrDefault().ToString() ; Console.WriteLine(name); Student stu1 = db.Students.Where(p=>p.StuId=="0001").FirstOrDefault() ; stu1.Name = "CYW"; db.SaveChanges(); name = db.Students.Select(p => p.Name).FirstOrDefault().ToString(); Console.WriteLine(name); } Console.ReadLine(); } } }
在上面代碼中,主要是先新增一個Student對象然后插入數據庫,打印輸出此時的name,然后通過數據庫上下文找到StuId=0001的學生,將name更改為CYW,
保存到數據庫再次打印數據name,從打印結果我們可以看到name最后是CYW,數據庫中最后的結果也是CYW。通過Profiler也能查看到sql執行的過程。




