Entity Framework 5.0系列之数据操作
Entity Framework將概念模型中定義的實體和關(guān)系映射到數(shù)據(jù)源,利用實體框架可以將數(shù)據(jù)源返回的數(shù)據(jù)具體化為對象;跟蹤對象所做的更改;并發(fā)處理;將對象 更改傳播到數(shù)據(jù)源等。今天我們就一起討論如何利用Entity Framework進行查詢、插入、更新和刪除數(shù)據(jù)。
查詢
我們將使用AdventureWorks數(shù)據(jù)庫來進行今天的所有演示,因此開始之前請準備好相應(yīng)的數(shù)據(jù)庫。在EF中進行查詢應(yīng)該說是相當簡單,只需 要定義一個類繼承于“DbContext”,然后定義對應(yīng)的“DbSet”集合屬性即可。例如下面的“AdventureWorksContext”類:
using System.Data.Entity; using System.Data.Entity.Infrastructure; using EFPowerTools.Models.Mapping; namespace EFPowerTools.Models { public partial class AdventureWorksContext : DbContext { static AdventureWorksContext() { Database.SetInitializer<AdventureWorksContext>(null); } public AdventureWorksContext() : base("Name=AdventureWorksContext") { } public DbSet<Employee> Employees { get; set; } public DbSet<Person> People { get; set; } } }
一個數(shù)據(jù)庫上下文的生命周期隨著該對象的創(chuàng)建而開始,隨著對象的釋放(或GC回收)而結(jié)束,因此建議在開發(fā)過程中使用“Using”編碼方式,這樣就可以免去手動釋放對象的操作。如下面的代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.Where(p => p.LastName == "Stevens").OrderBy(p=>p.FirstName); foreach(var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } }
另外對于數(shù)據(jù)庫連接的管理在EF中是透明的,我們一般不需要手動進行處理,當查詢一個對象時打開連接當處理完查詢的結(jié)果集之后會自動關(guān)閉連接。
在EF的Code First模式中有三種常用的數(shù)據(jù)查詢方式(Model First和Database First中還有其他方式如:使用Entity SQL,但這不是我們今天的重點):Linq To Entity表達式查詢、基于方法的查詢、原生SQL查詢。
Linq To Entity表達式查詢
查詢表達式是C#3.0新增的功能,它是由一組類似于T-SQL或XQuery聲明性語句組成,CLR并不能直接讀取這種查詢表達式而是在編譯時轉(zhuǎn)換為對應(yīng)的方法調(diào)用。如下面的例子:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = from p in db.People where p.LastName == "Stevens" orderby p.FirstName select p; foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } }
基于方法的查詢
基于方法的查詢事實上是一組對象的擴展方法,同Linq查詢不同的是這些方法可以直接被CLR識別并運行。
例如上面的方法我們可以轉(zhuǎn)換為如下代碼,他們的效果是一樣的,返回的都是“IQueryable”對象:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.Where(p => p.LastName == "Stevens").OrderBy(p => p.FirstName); foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } }
原生SQL查詢
EF還支持原生SQL查詢(注意與Entity SQL區(qū)別),例如:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.SqlQuery("SELECT * FROM Person.Person WHERE LastName='Stevens'"); foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } }
不僅如此,EF還支持非實體類型的查詢:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.Database.SqlQuery<string>("SELECT FirstName FROM Person.Person WHERE LastName='Stevens'").ToList(); foreach (var p in persons) { Console.WriteLine("FirstName:{0}", p); } } } } }
當然也支持無返回值的SQL命令:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { db.Database.ExecuteSqlCommand("UPDATE Person.Person SET NameStyle=1 WHERE BusinessEntityID='1813'"); } } } }
增加
在EF中添加操作一般有兩種方式:一是直接創(chuàng)建對象,然后調(diào)用“DbSet”的”Add()”方法進行添加;二是調(diào)用數(shù)據(jù)庫上下文的”Entry()”方法并設(shè)置對應(yīng)的狀態(tài)。無論使用哪種方式最終一定要調(diào)用“SaveChange()”進行提交。如:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var stephen = new Person { BusinessEntityID=20778, PersonType="EM", NameStyle=false, Title="Architec", FirstName="Stephen", LastName="Chow", EmailPromotion=1, rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; db.People.Add(stephen); var jeffrey = new Person { BusinessEntityID = 20779, PersonType = "EM", NameStyle = false, Title = "Engineer", FirstName = "Jeffrey", LastName = "Lee", EmailPromotion = 0, rowguid=Guid.NewGuid(), ModifiedDate=DateTime.Now }; db.Entry(jeffrey).State = EntityState.Added; db.SaveChanges(); } } } }
效果如圖:
此外,在含有導(dǎo)航屬性時,將一個對象賦值給另一個對象的導(dǎo)航屬性也能達到添加的效果(當導(dǎo)航屬性為”DbSet“集合時通過調(diào)用導(dǎo)航屬性的 “Add()“方法也同樣可以達到添加效果),例如在”Person.Person”中我們上面添加了兩條記錄,但對于“Person”類的導(dǎo)航屬性 “EmailAddress”和“Password”在對應(yīng)的“EmailAddress”表和“Password”表中并沒有添加對應(yīng)的記錄,此時我們 就可以通過下面的方式來增加:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var password = new Password { BusinessEntityID=20778, PasswordHash = "ZEgQH9qZIPiLgyBHYw/dD1FJQNpdQyIAa+BFfKX5/jg=", PasswordSalt = "7iy/umc=", rowguid=Guid.NewGuid(), ModifiedDate=DateTime.Now }; var email = new EmailAddress { BusinessEntityID = 20778, EmailAddress1 = "[email protected]", rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; var person = db.People.Find(20778); person.Password = password; person.EmailAddresses.Add(email); db.SaveChanges(); } } } }
此時查看將可以看到“EmailAddress”表中確實增加了一條記錄(“Password”表同樣也是如此):
狀態(tài)跟蹤
在這里我們需要強調(diào)一點那就是狀態(tài)跟蹤,對于上面的操作如果我們調(diào)用“Attach()”方法對實體進行跟蹤或者設(shè)置實體的狀態(tài)那么數(shù)據(jù)將不會保存到數(shù)據(jù)庫:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var stephen = new Person { BusinessEntityID = 20778, PersonType = "EM", NameStyle = false, Title = "Architec", FirstName = "Stephen", LastName = "Chow", EmailPromotion = 1, rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; db.People.Add(stephen); db.People.Attach(stephen); //db.Entry(stephen).State = EntityState.Unchanged;/同上面db.People.Attach(stephen);作用一樣 db.SaveChanges(); } } } }
使用”Attach()”方法進行實體跟蹤時會設(shè)置實體的狀態(tài)為“Unchanged”此時實體處于未修改狀態(tài),當執(zhí)行 “SaveChange()”方法時EF不會執(zhí)行修改操作。相反如果此時設(shè)置實體狀態(tài)為“Modified”則EF執(zhí)行更新操作。那么既然EF的數(shù)據(jù)修改 操作(增加、更新、刪除)是根據(jù)實體狀態(tài)而進行的,那么為什么之前我們的增加操作能正常進行而不用手動修改其狀態(tài)呢?原因是EF會自動發(fā)現(xiàn)狀態(tài)改變,在調(diào) 用下面的方法時狀態(tài)發(fā)現(xiàn)是自動的:
· DbSet.Find · DbSet.Local · DbSet.Remove · DbSet.Add · DbSet.Attach · DbContext.SaveChanges · DbContext.GetValidationErrors · DbContext.Entry · DbChangeTracker.Entries |
當然,并不是所有的時候我們都需要EF自動發(fā)現(xiàn)狀態(tài)改變,設(shè)置 “DbContext.Configuration.AutoDetectChangesEnabled”屬性為“false”可以禁用自動發(fā)現(xiàn)功能。
![]() |
注意:在EF對數(shù)據(jù)操作時有時會拋出: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 此時可以使用try{} catch(DbEntityValidationException ex){} 對異常進行捕獲,將鼠標放到ex上并逐級查看ex的信息進行解決。 |
刪除
下面看一下EF的刪除操作:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19977).FirstOrDefault(); db.EmailAddresses.Remove(mail); db.SaveChanges(); } } } }
當然有了上面狀態(tài)跟蹤的討論相信大家也可以想到如下刪除方法:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19976).FirstOrDefault(); db.Entry(mail).State = EntityState.Deleted; db.SaveChanges(); } } } }
修改
修改數(shù)據(jù)很簡單,直接修改對應(yīng)的屬性即可:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var person = db.People.Where(p => p.LastName == "Stevens").OrderBy(p=>p.BusinessEntityID).FirstOrDefault(); person.NameStyle = false; person.EmailAddresses.First().EmailAddress1 = "[email protected]"; db.SaveChanges(); } } } }
需要說明的是,EF在執(zhí)行修改操作前會檢查哪些屬性發(fā)生了變化,并且只會修改發(fā)生變化的字段。
今天的內(nèi)容就先到這里了,從前面的EF5.0概覽到現(xiàn)在的數(shù)據(jù)操作,關(guān)于EF5.0基礎(chǔ)的入門內(nèi)容已經(jīng)說完了,更多內(nèi)容敬請關(guān)注后面的文章。
1
2
3
4
5
6
7
8
9
|
- (void)configDelegate{
__weaktypeof(self)weakSelf=self;
[self.delegatesetSelectRowAtIndexPathBlock:^(idcell,NSIndexPath*indexPath) {
TMPremiereBrand*premiereBrand= (TMPremiereBrand*)weakSelf.data[indexPath.row];
TMSpecialTopicController*specialTopicController= [[TMSpecialTopicControlleralloc]init];
specialTopicController.premiereBrandID=premiereBrand.ID;
[weakSelf.navigationControllerpushViewController:specialTopicControlleranimated:YES];
}];
}
|