天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

使用LINQ to SQL更新數(shù)據(jù)庫(中):幾種解決方案

前一篇文章中,我提出了在使用LINQ to SQL進行更新操作時可能會遇到的幾種問題。其實這并不是我一個人遇到的問題,當我在互聯(lián)網(wǎng)上尋找答案時,我發(fā)現(xiàn)很多人都對這個話題發(fā)表過類似文章。但另我無法滿足的是,他們盡管提出了問題,卻沒有進行詳細的剖析,只給出了解決方案(如添加RowVersion列、去除關聯(lián)等),但卻沒有說明為什么必須這么做。這也是我寫上篇的初衷,希望通過對LINQ to SQL源代碼的分析,來一步一步找出解決問題的辦法。本文將對這些方法一一進行討論。

方案一:重新賦值

TerryLeeAnytaoDing Xue等人的開源框架Ezsocio中,有些地方采取了重新賦值的方法。在Update方法內(nèi)部,根據(jù)主鍵獲取數(shù)據(jù)庫中的實體,然后與參數(shù)中的實體對其屬性一一賦值。

public void UpdateProfile(Profile p){    using (RepositoryContext db = new RepositoryContext())    {        var profile = db.GetTable<Profile>().First<Profile>(u => u.ID == p.ID);        profile.Birthday = p.Birthday;        profile.Gender = p.Gender;        profile.Hometown = p.Hometown;        profile.MSN = p.MSN;        profile.NickName = p.NickName;        profile.PhoneNumber = p.PhoneNumber;        profile.QQ = p.QQ;        profile.State = p.State;        profile.TrueName = p.TrueName;        profile.StateRefreshTime = p.StateRefreshTime;        profile.Avatar = p.Avatar;        profile.Website = p.Website;        db.SubmitChanges();    }}

楊過兄也同樣給出了該方案的反射方法,實現(xiàn)屬性值的自動拷貝。

但我個人認為這是一種避實就虛的方案,沒有使用LINQ to SQL提供的用于更新操作的API,而采取了一種迂回的策略。這其實是一種妥協(xié),難道因為Attach方法“不好用”,我們就不用了嗎?呵呵。

方案二:禁用對象跟蹤

對此,lea提出可以通過將DataContext的ObjectTrackingEnabled屬性設置為false,來達到正確更新的目的。

public Product GetProduct(int id){    NorthwindDataContext db = new NorthwindDataContext();    db.ObjectTrackingEnabled = false;    return db.Products.SingleOrDefault(p => p.ProductID == id);}

其他的代碼沒有任何變化。

為什么禁用對象跟蹤之后,就能正常更新了呢?我們還是從源代碼中來尋找答案吧。

public bool ObjectTrackingEnabled{    get    {        this.CheckDispose();        return this.objectTrackingEnabled;    }    set    {        this.CheckDispose();        if (this.Services.HasCachedObjects)        {            throw System.Data.Linq.Error.OptionsCannotBeModifiedAfterQuery();        }        this.objectTrackingEnabled = value;        if (!this.objectTrackingEnabled)        {            this.deferredLoadingEnabled = false;        }        this.services.ResetServices();    }}

原來設置ObjectTrackingEnabled為false時,會同時將DeferredLoadingEnabled設置為false。這樣,在執(zhí)行查詢時,將不會為實體加載任何需延遲查詢的數(shù)據(jù),因此Attach時也不會拋出異常(見上篇的分析)。

在MSDN中我們還得到下面這條有用的信息:將ObjectTrackingEnable屬性設置為false,可以提高檢索時的性能,因為這樣可以減少要跟蹤的項目。這真是一個很有誘惑的特性。

但禁用對象跟蹤時,要特別注意兩點:(1)必須在執(zhí)行查詢前禁用。(2)禁用之后不能再調(diào)用Attach和SubmitChanges方法。否則都將引發(fā)異常。

方案三:移除關聯(lián)

前一篇文章中已經(jīng)介紹一個蹩腳的方法,即在GetProduct方法中手動設置與Product關聯(lián)的Category為null。我們可以把這部分代碼提取出來,放入一個Detach方法中。因為這個Detach是實體的方法,可以使用分部類:

public partial class Product{    public void Detach()    {        this._Category = default(EntityRef<Category>);    }}public partial class Category{    public void Detach()    {        foreach (var product in this.Products)        {            product.Detach();        }    }}

但是這種對每個實體都定義Detach的方法過于繁瑣。隨著實體的增多,關系越來越復雜,很容易出現(xiàn)漏掉的屬性。張逸提出了一個非常優(yōu)雅的方法,利用反射對該邏輯進行抽象:

private void Detach(TEntity entity){    foreach (FieldInfo fi in entity.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.
Instance)) {
if (fi.FieldType.ToString().Contains("EntityRef")) { var value = fi.GetValue(entity); if (value != null) { fi.SetValue(entity, null); } } if (fi.FieldType.ToString().Contains("EntitySet")) { var value = fi.GetValue(entity); if (value != null) { MethodInfo mi = value.GetType().GetMethod("Clear"); if (mi != null) { mi.Invoke(value, null); } fi.SetValue(entity, value); } } }}

也有人認為在Detach時應該把PropertyChanging和PropertyChanged事件設置為null,但總體的思路是一樣的。

方案四:使用委托

這是ZC29同學在我上一篇文章的評論里給出的方法,我個人認為非常值得借鑒。

public void UpdateProductWithDelegate(Expression<Func<Product, bool>> predicate, Action
<
Product> action){ NorthwindDataContext db = new NorthwindDataContext(); var product = db.Products.SingleOrDefault(predicate); action(product); db.SubmitChanges();}// Client codeProductRepository repository = new ProductRepository();repository.UpdateProductWithDelegate(p => p.ProductID == 1, p => { p.ProductName = "Changed"; });

使用Lambda表達式將GetProduct的邏輯植入UpdateProduct中,并且使用委托將更新邏輯也延緩執(zhí)行,這樣巧妙地將查找和更新放進了一個DataContext里,從而繞開了Attach。但是這種方法API有些過于復雜,對客戶端編程人員的水平要求過高。而且在Update里還要執(zhí)行一遍Get的邏輯,盡管性能上的損失微乎其微,但看上去總多多少少給人一種不夠DRY的感覺。

方案五:使用UPDATE語句

Ezsocio的源代碼中,我發(fā)現(xiàn)了RepositoryBase.UpdateEntity方法。在方法內(nèi)部進行SQL語句的拼接,并且將只更新發(fā)生更改的列。由于此處已經(jīng)不再使用ITable,并且需要完整的框架支持,因此不再進行過多的評述。詳情請參考Ezsocio的源代碼。

總結(jié)

本文列舉了近幾天我在互聯(lián)網(wǎng)上找到的幾種解決方案,它們各有利弊,孰優(yōu)孰劣,見仁見智。在下篇中,我將對這幾種方法進行性能上的比較,從而找出最優(yōu)方案。

相關文章

NET技術(shù)使用LINQ to SQL更新數(shù)據(jù)庫(中):幾種解決方案,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 亚洲 自拍 偷拍 另类综合图区 | 欧美牲交A欧美牲交VDO | 菠萝菠萝蜜高清观看在线 | 十分钟免费视频大全在线观看 | 欧美白人极品性喷潮 | 国产睡熟迷奷系列网站 | 日日夜夜影院在线播放 | 成人在线不卡视频 | 精彩国产萝视频在线 | 亚洲精品91 | 超碰97av 在线人人操 | 丰满饥渴老太性hd | 男总裁憋尿PLAY灌尿BL | 99国产小视频 | 99视频精品国产在线视频 | 男女边吃奶边做边爱视频 | 日本精品久久久久中文字幕 | 国产偷国产偷亚州清高APP | 中文字幕国产视频 | 国产嫩草影院精品免费网址 | 秋霞电影在线观看午夜伦 | 邻居的阿2中文字版电影 | 91免费永久在线地址 | 免费视频国产 | 国产a级午夜毛片 | 果冻传媒9CM在线观看 | 免费毛片在线视频 | 亚洲国产五月综合网 | 萝莉御姐被吸奶 | 最近中文字幕无吗免费高清 | 妇少水多18P蜜泬17P亚洲乱 | 樱桃熟了A级毛片 | 动听968| 中文字幕乱码在线人视频 | 双性h浪荡受bl | 97蜜桃123 | 国内精品久久久久影院男同志 | 菠萝菠萝蜜免费播放高清 | 久久久久亚洲 | 日本高清天码一区在线播放 | 色鲁97精品国产亚洲AV高 |