1、什麼是Entity Frameworksql
微軟官方提供的ORM工具,ORM讓開發人員節省數據庫訪問的代碼時間,將更多的時間放到業務邏輯層代碼上。EF提供變動跟蹤、惟一性約束、惰性加載、查詢事物等。開發人員使用Linq語言,對數據庫操做如同操做Object對象同樣省事。數據庫
EF有三種使用場景,1. 從數據庫生成Class,2.由實體類生成數據庫表結構,3. 經過數據庫可視化設計器設計數據庫,同時生成實體類。express
O/RM是什麼?api
ORM 是將數據存儲從域對象自動映射到關係型數據庫的工具。ORM主要包括3個部分:域對象、關係數據庫對象、映射關係。ORM使類提供自動化CRUD,使開發人員從數據庫API和SQL中解放出來。瀏覽器
2、Entity Framework 架構緩存
EDM (實體數據模型):EDM包括三個模型,概念模型、 映射和存儲模型。架構
概念模型 ︰ 概念模型包含模型類和它們之間的關係。獨立於數據庫表的設計。併發
存儲模型 ︰ 存儲模型是數據庫設計模型,包括表、 視圖、 存儲的過程和他們的關係和鍵。app
映射 ︰ 映射包含有關如何將概念模型映射到存儲模型的信息。數據庫設計
LINQ to Entities ︰ LINQ to Entities 是一種用於編寫針對對象模型的查詢的查詢語言。它返回在概念模型中定義的實體。
Entity SQL: Entity SQL 是另外一種爐相似於L2E的言語,但相給L2E要複雜的多,因此開發人員不得不單獨學習它。
Object Services(對象服務):是數據庫的訪問入口,負責數據具體化,從客戶端實體數據到數據庫記錄以及從數據庫記錄和實體數據的轉換。
Entity Client Data Provider:主要職責是將L2E或Entity Sql轉換成數據庫能夠識別的Sql查詢語句,它使用Ado.net通訊向數據庫發送數據可獲取數據。
ADO.Net Data Provider:使用標準的Ado.net與數據庫通訊
3、Entity Framework運行環境
EF5由兩部分組成,EF api和.net framework 4.0/4.5,而EF6是獨立的EntityFramework.dll,不依賴.net Framework。使用NuGet便可安裝EF。
4、建立實體數據模型
使用嚮導建立實體類,或鍵添加,傻瓜式的~
添加完成以後,.config文件中會添加如下配置
<?xmlversion="1.0"?><configuration><configSections><!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --><sectionname="entityFramework"type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"requirePermission="false"/></configSections><startup><supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.5"/></startup><entityFramework><defaultConnectionFactorytype="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/><providers><providerinvariantName="System.Data.SqlClient"type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/></providers></entityFramework><connectionStrings><addname="SchoolDBEntities"connectionString="metadata=res://*/SchoolDB.csdl|res://*/SchoolDB.ssdl|res://*/SchoolDB.msl;provider=System.Data.SqlClient;provider connection string="data source=.\sqlexpress;initial catalog=SchoolDB;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework""providerName="System.Data.EntityClient"/></connectionStrings></configuration>
Context & Entity 類:
每一個Entity Data Model 生成一個context類,類數據庫每一個表生成一個entity類。如在School.edmx中包含的兩個重要的文件{EDM Name}.context.tt和{EDM Name}.tt:
School.Context.tt:T4模板用於生成的context類,能夠從目錄結構中看到School.Context.tt下包含一個School.Context.cs文件。
School.tt:用於生成表映射的實體類。Entity類是POCO類。如Student生成
publicpartialclassStudent
{
public Student()
{
this.Courses = new HashSet<Course>();
}
publicint StudentID { get; set; }
publicstring StudentName { get; set; }
publicNullable<int> StandardId { get; set; }
publicbyte[] RowVersion { get; set; }
publicvirtualStandard Standard { get; set; }
publicvirtualStudentAddress StudentAddress { get; set; }
publicvirtualICollection<Course> Courses { get; set; }
}
5、模板瀏覽器
以SchoolDB爲例,切換到Model View視圖下,看到類圖結構:
6、DBContext
第四節中提到EDM生成SchoolDBEntities類,該類從System.Data.Entity.DbContext類繼承。EntityFramework4.1中Context類從ObjectContext類繼承。DbContext類與ObjectContext相似,它對ObjcetContext類進行包裝更利於開發的三種模式:CodeFirst、Model First、Database First.
DbContext是EntityFramework很重要的部分,鏈接域模型與數據庫的橋樑,是與數據庫通訊的主要類。
DbContext主要負責如下活動:
EntitySet::DbContext包含了全部映射到表的entities
Querying:將Linq-To-Entities轉譯爲Sql併發送到數據庫
Change Tracking:從數據庫獲取entities後保留並跟蹤實體數據變化
Persisting Data:根據entity狀態執行Insert、update、delete命令
Caching:DbContext的默認第一級緩存,在上下文中的生命週期中存儲entity
Manage Relationship:DbContext在DbFirst模式中使用CSDL、MSL、SSDL管理對象關係,Code first中使用fluent api 管理關係
Object Materialization:DbContext將物理錶轉成entity實例對象
DEMO
DbContext實例化:
using (var ctx = newSchoolDBEntities())
{
//Can perform CRUD operation using ctx here..
}
將DbContext轉爲ObjectContext
using (var ctx = newSchoolDBEntities())
{
var objectContext = (ctx as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext;
//use objectContext here..
}
7、Entity Framework中的Entity類型
POCO Entity (Plain Old CLR Object):
不依賴於任何Framework的類的類(also known as persistence-ignorant objects),爲Entity Data Model生成CRUD命令服務。
public class Student
{
public Student()
{
this.Courses = new List<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public Standard Standard { get; set; }
public StudentAddress StudentAddress { get; set; }
public IList<Course> Courses { get; set; }
}
Dynamic Proxy (POCO Proxy):
Dynamic Proxy是運行時POCO類的代理類,相似POCO類的包裝。Dynamic Proxy容許延遲加載(Lazy loading),自動跟蹤更改。POCO Entity必需知足如下幾點才能轉爲POCO Proxy:
1. 必需聲明爲public 類
2. 不能夠是sealed類
3. 不能夠是抽象類
4. 導航屬性必需是public,vitual(Entity包含兩種屬性,標量屬性Scalar properties:Entity自己的字段值,Navigation properties:其它entity的引用如班級-學生)
5. 集合屬性必需是 ICollection<T>
6. ProxyCreationEnabled 選項必需是true
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
8、Entity Relationships:
9、 Entity Lifecycle
在咱們作CRUD操做時,要先了解EntityFramework如何管理實體狀態。每一個實體的生命週期內都會在DbContext上下文中保存一個狀態,分別是
Added Deleted Modified Unchanged Detached
10、Code First、DBFirst、Model First
CodeFirst 領域設計時先定義實體類,用實體類生成數據庫
DbFirst 從數據庫生成實體類
Model First 使用Visual Studio實體設計器,設計ER,同時生成Entity類和DB
11、使用查詢
三種查詢方式1) LINQ to Entities, 2) Entity SQL, and 3) Native SQL
LINQ to Entities:
LINQ Method syntax:
//Querying with LINQ to Entities
using (var context = newSchoolDBEntities())
{
var L2EQuery = context.Students.where(s => s.StudentName == "Bill");
var student = L2EQuery.FirstOrDefault<Student>();
}
LINQ Query syntax:
using (var context = new SchoolDBEntities())
{
var L2EQuery = from st in context.Students
where st.StudentName == "Bill"select st;
var student = L2EQuery.FirstOrDefault<Student>();
}
Entity SQL:
//Querying with Object Services and Entity SQL
string sqlString = "SELECT VALUE st FROM SchoolDBEntities.Students " +
"AS st WHERE st.StudentName == 'Bill'";
var objctx = (ctx as IObjectContextAdapter).ObjectContext;
ObjectQuery<Student> student = objctx.CreateQuery<Student>(sqlString);
Student newStudent = student.First<Student>();
//使用EntityDataReader
using (var con = newEntityConnection("name=SchoolDBEntities"))
{
con.Open();
EntityCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT VALUE st FROM SchoolDBEntities.Students as st where st.StudentName='Bill'";
Dictionary<int, string> dict = newDictionary<int, string>();
using (EntityDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess |CommandBehavior.CloseConnection))
{
while (rdr.Read())
{
int a = rdr.GetInt32(0);
var b = rdr.GetString(1);
dict.Add(a, b);
}
}
}
Native SQL:
using (var ctx = newSchoolDBEntities())
{
var studentName = ctx.Students.SqlQuery("Select studentid, studentname, standardId from Student where studentname='Bill'").FirstOrDefault<Student>();
}
12、跟蹤變動與持久化場景
在鏈接狀態下持久化與脫機狀態下持久化
連機狀態下持久化,在同一個DbContext中不須要銷燬Entity,直接寫入數據庫
脫機狀態持久化指讀取和保存Entity在兩個不一樣的DbContext中,Context2不知道Entity的更新狀態,因此必需通知Context2當前的Entity作了何種更新。
Context只在DbSet上跟蹤添加和刪除
正確的添加和刪除
using (var context = new SchoolDBEntities())
{
var studentList = context.Students.ToList<Student>();
//Perform create operation
context.Students.Add(newStudent() { StudentName = "New Student" });
//Perform Update operationStudent studentToUpdate = studentList.Where(s => s.StudentName =="student1").FirstOrDefault<Student>();
studentToUpdate.StudentName = "Edited student1";
//Perform delete operation
context.Students.Remove(studentList.ElementAt<Student>(0));
//Execute Inser, Update & Delete queries in the database
context.SaveChanges();
}
如下代碼在List中添加和刪除不起做用,只有更生有效
using (var context = new SchoolDBEntities())
{
var studentList = context.Students.ToList<Student>();
//Add student in list
studentList.Add(new Student() { StudentName = "New Student" });
//Perform update operationStudent studentToUpdate = studentList.Where(s => s.StudentName =="Student1").FirstOrDefault<Student>();
studentToUpdate.StudentName = "Edited student1";
//Delete student from listif (studentList.Count > 0)
studentList.Remove(studentList.ElementAt<Student>(0));
//SaveChanges will only do update operation not add and delete
context.SaveChanges();
}
脫機實體
脫機實體管理要先附加到Context
//disconnected entity graphStudent disconnectedStudent = newStudent() { StudentName = "New Student" };
disconnectedStudent.StudentAddress = newStudentAddress() { Address1 = "Address", City = "City1" };
using (var ctx = newSchoolDBEntities())
{
//attach disconnected Student entity graph to new context instance - ctx
ctx.Students.Attach(disconnectedStudent);
// get DbEntityEntry instance to check the EntityState of specified entity
var studentEntry = ctx.Entry(disconnectedStudent);
var addressEntry = ctx.Entry(disconnectedStudent.StudentAddress);
Console.WriteLine("Student EntityState: {0}",studentEntry.State);
Console.WriteLine("StudentAddress EntityState: {0}",addressEntry.State);
}
添加多個關係實體時與添加單個實體同樣,更新關係實體時須要跟蹤每一個實體的狀態。
十三 Entity Framework併發處理
添加RowVersion,類型爲TimeStamp字段,在EDM中X修改併發屬性爲Fixed。EF更新實體時會先檢查RowVersion,若是發現RowVersion不一致,則拋出DbUpdateConcurrencyException異常
十四 貪婪加載、惰性加載與定向加載
貪婪加載:使用Include(),自動加載關聯實體
using (var context = new SchoolDBEntities())
{
var res = (from s in context.Students.Include("Standard")
where s.StudentName == "Student1"
select s).FirstOrDefault<Student>();
}
執行Sql
SELECTTOP (1)
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent2].[StandardId] AS [StandardId],
[Extent2].[StandardName] AS [StandardName],
[Extent2].[Description] AS [Description]
FROM [dbo].[Student] AS [Extent1]
LEFTOUTERJOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId] = [Extent2].[StandardId]
WHERE'Student1' = [Extent1].[StudentName]
惰性加載:延遲加載對象關聯的實體,用到時再加載,EF默認爲LazyLoading
using (var ctx = newSchoolDBEntities())
{
//Loading students onlyIList<Student> studList = ctx.Students.ToList<Student>();
Student std = studList[0];
//Loads Student address for particular Student only (seperate SQL query)
StudentAddress add = std.StudentAddress;
}
定向加載:Reference()和Collection() 方法
using (var context = new SchoolDBEntities())
{
//Loading students only
IList<Student> studList = context.Students.ToList<Student>();
Student std = studList.Where(s => s.StudentID == 1).FirstOrDefault<Student>();
//Loads Standard for particular Student only (seperate SQL query)
context.Entry(std).Reference(s => s.Standard).Load();
//Loads Courses for particular Student only (seperate SQL query)
context.Entry(std).Collection(s => s.Courses).Load();
}
十五:執行SQL
返回實體
using (var ctx = newSchoolDBEntities())
{
//列名必須要Entity屬性匹配
var studentList = ctx.Students.SqlQuery("Select * from Student").ToList<Student>();
}
返回非實體類型
using (var ctx = newSchoolDBEntities())
{
//Get student name of string typestring studentName = ctx.Database.SqlQuery<string>("Select studentname
from Student where studentid=1").FirstOrDefault<string>();
}
執行SQL命令
using (var ctx = new SchoolDBEntities())
{
//Update commandint noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update student
set studentname ='changed student by command' where studentid=1");
//Insert commandint noOfRowInserted = ctx.Database.ExecuteSqlCommand("insert into student(studentname)
values('New Student')");
//Delete commandint noOfRowDeleted = ctx.Database.ExecuteSqlCommand("delete from student
where studentid=1");
}
---
--