Entity Framework 基础
一、什么是Entity Framework
? ? 微軟官方提供的ORM工具,ORM讓開發人員節省數據庫訪問的代碼時間,將更多的時間放到業務邏輯層代碼上。EF提供變更跟蹤、唯一性約束、惰性加載、查詢事物等。開發人員使用Linq語言,對數據庫操作如同操作Object對象一樣省事。
? ? EF有三種使用場景,1. 從數據庫生成Class,2.由實體類生成數據庫表結構,3. ?通過數據庫可視化設計器設計數據庫,同時生成實體類。
?
O/RM是什么?
? ? ORM?是將數據存儲從域對象自動映射到關系型數據庫的工具。ORM主要包括3個部分:域對象、關系數據庫對象、映射關系。ORM使類提供自動化CRUD,使開發人員從數據庫API和SQL中解放出來。
二、Entity?Framework 架構
EDM?(實體數據模型):EDM包括三個模型,概念模型、?映射和存儲模型。
概念模型?︰?概念模型包含模型類和它們之間的關系。獨立于數據庫表的設計。
存儲模型?︰?存儲模型是數據庫設計模型,包括表、?視圖、?存儲的過程和他們的關系和鍵。
映射?︰?映射包含有關如何將概念模型映射到存儲模型的信息。
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與數據庫通信
?
三、Entity Framework運行環境
EF5由兩部分組成,EF api和.net framework 4.0/4.5,而EF6是獨立的EntityFramework.dll,不依賴.net Framework。使用NuGet即可安裝EF。
? ??
?
四、創建實體數據模型
使用向導創建實體類,或鍵添加,傻瓜式的~
添加完成之后,.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; }
}
五、模板瀏覽器
以SchoolDB為例,切換到Model View視圖下,看到類圖結構:
?
六、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..
}
?
?
七、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; }
}
?
八、Entity?Relationships:
?
九、?Entity?Lifecycle
? ??在我們做CRUD操作時,要先了解EntityFramework如何管理實體狀態。每個實體的生命周期內都會在DbContext上下文中保存一個狀態,分別是
Added?Deleted?Modified?Unchanged?Detached
十、Code First、DBFirst、Model First
CodeFirst 領域設計時先定義實體類,用實體類生成數據庫
DbFirst 從數據庫生成實體類
Model First 使用Visual Studio實體設計器,設計ER,同時生成Entity類和DB
十一、使用查詢
三種查詢方式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>();
}
?
十二、跟蹤變更與持久化場景
在連接狀態下持久化與脫機狀態下持久化
連機狀態下持久化,在同一個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");
?
}
?
?
?
---
--
轉載于:https://www.cnblogs.com/sjqq/p/6957034.html
總結
以上是生活随笔為你收集整理的Entity Framework 基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小看--发布-订阅(观察者)模式
- 下一篇: 【bzoj4916】神犇和蒟蒻 杜教筛