天天看點

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

要專業系統地學習EF前往《你必須掌握的Entity Framework 6.x與Core 2.0》這本書的作者(汪鵬,Jeffcky)的部落格:https://www.cnblogs.com/CreateMyself/

資料操作CRUD,我們隻說Update,因為在EF中Update有點複雜  後面我們說批量資料更新

Update操作

上下文沒有提供Update方法,是以我們要更新操作一般都是将資料查詢出來,修改實體屬性的值,然後SaveChanges()就OK了

眼熟一下平時的Update

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//一般的修改

var pro =ctx.Products.FirstOrDefault();

Console.WriteLine(JsonConvert.SerializeObject(pro));

Console.WriteLine(ctx.Entry(pro).State);//Unchanged//{"Order":null,"Name":"牙刷","Price":14.00,"Unit":"隻","FK_Order_Id":"82903023-a7a6-4839-9caa-153ee9d00e65","Id":"1b25351c-3008-4d27-a9de-6749ec1d0845","AddTime":"2019-01-15T10:35:03.947"}

pro.Name = "牙刷2";

Console.WriteLine(ctx.Entry(pro).State);//Modified

var res =ctx.SaveChanges();

Console.WriteLine(res);//result:1

View Code

查詢出來沒做修改的實體,狀态為Unchange,修改了屬性值,狀态變為Modified

現在要是我憑空new一個Product對象,id設定為資料庫中某一個産品的Id,然後讓上下文對這個新對象追蹤,最後再修改實體狀态為Modified,看看能不能修改

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//資料庫中存在的某一條資料的Id

string id = "b0465c73-a7ab-4135-9bf8-4ec85ac6b1e2";

Product p= newProduct

{

Id=id,

Name= "娃哈哈",

AddTime=DateTime.Now,

Price= 3,

Unit= "瓶"};

Console.WriteLine(ctx.Entry(p).State);//Detached

ctx.Products.Attach(p); //這裡報錯

View Code

失敗,在我對它進行追蹤時就報錯了。因為不能跟蹤多個相同鍵的實體,就和資料庫中主鍵重複沖突一樣

System.InvalidOperationException: Attaching an entity of type '_2019011402.Entity.Product' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

解決辦法就是,去掉一個追蹤,那麼我們把該條資料查詢出來,對它取消追蹤,這個再跟蹤這個新對象就可以了

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//全部屬性更新

var pro = ctx.Products.AsNoTracking().FirstOrDefault(x =>x.Id.Contains(id));

Console.WriteLine(ctx.Entry(pro).State);//Detached

Product p = newProduct

{

Id=id,

Name= "娃哈哈",

AddTime=DateTime.Now,

Price= 3,

Unit= "瓶",

FK_Order_Id= "469b82be-8139-4e67-b566-5b2b5f6d838d"};

ctx.Products.Attach(p);

ctx.Entry(p).State=System.Data.Entity.EntityState.Modified;var res =ctx.SaveChanges();

Console.WriteLine(res);//result:1 ok

View Code

然後我貼一段代碼,和主題沒什麼關系

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//我來聲明兩個變量查詢資料庫中的同一條記錄,引用相等

var pro2 = ctx.Products.FirstOrDefault(x =>x.Id.Contains(id));var pro3 = ctx.Products.FirstOrDefault(x =>x.Id.Contains(id));

Console.WriteLine("pro2_state:{0}", ctx.Entry(pro2).State); //Unchanged

Console.WriteLine("pro3_state:{0}", ctx.Entry(pro3).State); //Unchanged

Console.WriteLine(ReferenceEquals(pro2, pro3));//True

Test t1 = new Test { Id = "id1", Name = "Test1"};

Test t2= new Test { Id = "id1", Name = "Test1"};

Console.WriteLine(ReferenceEquals(t1, t2));//False

View Code

接着看Update操作,如果我們隻更新一個實體的部分屬性呢?

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//部分屬性更新,少了name,unit

var pro = ctx.Products.AsNoTracking().FirstOrDefault(x =>x.Id.Contains(id));

Console.WriteLine(ctx.Entry(pro).State);//Detached

Product p = newProduct

{

Id=id,

AddTime=DateTime.Now,

Price= 3,

FK_Order_Id= "469b82be-8139-4e67-b566-5b2b5f6d838d"};

ctx.Products.Attach(p);

ctx.Entry(p).State=System.Data.Entity.EntityState.Modified;var res =ctx.SaveChanges();

Console.WriteLine(res);//result:1 ok

View Code

看看資料庫中的情況

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

上面的情況說明Modified是全部更新,不能部分更新

部分更新

那麼怎麼部分更新?書中給了兩種辦法

1.手動指定更新屬性

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

ctx.Entry(p).Property(x => x.Name).IsModified = true;

ctx.Entry(p).Property(x=> x.Unit).IsModified = true;

View Code

2.用Entry().CurrentValues.SetValues() 方法

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

//使用 Entry()..CurrentValues.SetValues() 方式

var pro = ctx.Products.FirstOrDefault(x =>x.Id.Contains(id));

Product p= newProduct

{

Id=id,

Name= "盆子2",//AddTime = new DateTime(1999, 2, 2),//Price = 3,

Unit = "個2",

FK_Order_Id= "469b82be-8139-4e67-b566-5b2b5f6d838d"};

ctx.Entry(pro).CurrentValues.SetValues(p);

ctx.SaveChanges();

View Code

但是我使用了之後,覺得不太好,也不知道是不是用錯了,我遇到的問題是這樣的,無法部分更新

比如資料庫中存在這麼一條資料{"id":"123",”"name":"張三","age":25,"FK_AddressId":"234"},那麼我現在隻想更新Name,我就傳遞這個對象{"id":"123","name":"趙四"},但是它還是全部更新

比如我沒有指定age屬性,那麼修改為預設值“0”,外鍵在資料庫中不能為空,報錯

各位可以去弄一下

批量更新操作

平時做批量更新,那就是周遊修改呗

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

var products =ctx.Products.ToList();foreach (var item inproducts)

{

item.Name= item.Name + "999";

}

ctx.SaveChanges();

View Code

看看EF生成并執行的SQL語句

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

他會先把要更新的資料查詢出來,然後逐條更新,如果你建立了存儲過程,那麼他會自動調用存儲過程進行更新,這個性能會好一點

我這裡有一個存儲過程

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

然後真正的SQL執行是這樣的

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

他首先會将要更新的資料查詢出來,然後調用多次存儲過程

還是覺得不太理想?那麼作者告訴了我們一個更好的方案,使用第三方庫:EntityFrameWork.Extended

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

引入命名空間:using EntityFramework.Extensions; 然後調用該Update方法

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

var products = ctx.Products.Update(x => new Product { Name = x.Name + "777"});

ctx.SaveChanges();

View Code

捕獲到SQL語句是這樣的,很奇怪用ctx.Database.Log = Console.WriteLine;捕獲不到,我用的SQL Profiler,這應該是這個Extended庫是第三方的原因,不是EF團隊弄的

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作
efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

UPDATE [dbo].[tb_Products] SET

[Name] = CASE WHEN ([Name] IS NULL) THEN N'' ELSE [Name] END + N'777'

FROM [dbo].[tb_Products] AS j0 INNER JOIN(SELECT

1 AS [C1],[Extent1].[Id] AS [Id]

FROM [dbo].[tb_Products] AS [Extent1])AS j1 ON (j0.[Id] = j1.[Id])

View Code

看看資料庫裡面

efcore 批量_EF6學習筆記十二:Update操作、批量資料操作

唉,也難怪别人都說EF性能不好,還有很多東西要學啊。