亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

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

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

方案一:重新賦值
在TerryLee、Anytao和Ding Xue等人的開源框架Ezsocio中,有些地方采取了重新賦值的方法。在Update方法內部,根據主鍵獲取數據庫中的實體,然后與參數中的實體對其屬性一一賦值。

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();
    }
}
楊過兄也同樣給出了該方案的反射方法,實現屬性值的自動拷貝。

但我個人認為這是一種避實就虛的方案,沒有使用LINQ to SQL提供的用于更新操作的API,而采取了一種迂回的策略。這其實是一種妥協,難道因為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。這樣,在執行查詢時,將不會為實體加載任何需延遲查詢的數據,因此Attach時也不會拋出異常(見上篇的分析)。

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

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

方案三:移除關聯
在前一篇文章中已經介紹一個蹩腳的方法,即在GetProduct方法中手動設置與Product關聯的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的方法過于繁瑣。隨著實體的增多,關系越來越復雜,很容易出現漏掉的屬性。張逸提出了一個非常優雅的方法,利用反射對該邏輯進行抽象:

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 code
ProductRepository repository = new ProductRepository();
repository.UpdateProductWithDelegate(p => p.ProductID == 1, p =>
    {
        p.ProductName = "Changed";
    });
使用Lambda表達式將GetProduct的邏輯植入UpdateProduct中,并且使用委托將更新邏輯也延緩執行,這樣巧妙地將查找和更新放進了一個DataContext里,從而繞開了Attach。但是這種方法API有些過于復雜,對客戶端編程人員的水平要求過高。而且在Update里還要執行一遍Get的邏輯,盡管性能上的損失微乎其微,但看上去總多多少少給人一種不夠DRY的感覺。

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

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品女主播| 国产性猛交xxxx免费看久久| 97视频在线观看亚洲| 亚洲天堂久久av| 国产精品夜色7777狼人| 国产精品偷伦一区二区| 久久久久久久久久久成人| 欧美亚洲一级片| 国产综合久久久久久| **欧美日韩vr在线| 日韩精品免费在线视频观看| 亚洲电影免费观看高清完整版在线| 黄色成人在线免费| 中文字幕久久久av一区| 欧美精品videosex牲欧美| 国产精品久久9| 国产精品成人一区二区三区吃奶| 欧美在线观看一区二区三区| 日韩精品高清在线观看| 日韩二区三区在线| 精品久久久久久久久久久| 久久久久久亚洲精品不卡| 美女性感视频久久久| 中文字幕亚洲综合久久| 成人av在线天堂| 欧美视频裸体精品| 欧美日韩国产一区中文午夜| 激情成人在线视频| 欧美成年人视频| 亚洲精品中文字幕av| 91久久精品国产| 国产精品偷伦免费视频观看的| 国产精品av免费在线观看| 亚洲国产欧美一区二区三区同亚洲| 国产亚洲精品久久久久久777| 性视频1819p久久| 最近2019免费中文字幕视频三| 亚洲天堂av在线免费观看| 欧美黄色免费网站| 亚洲午夜精品久久久久久性色| 久久久91精品国产一区不卡| 国产视频亚洲视频| 日韩免费在线视频| 清纯唯美亚洲综合| 久久69精品久久久久久国产越南| 国产成人高潮免费观看精品| 欧美亚洲视频一区二区| 福利一区视频在线观看| 日韩av在线影视| 黑人巨大精品欧美一区二区一视频| 成人黄色免费网站在线观看| 亚洲精选一区二区| 欧美日本啪啪无遮挡网站| 国产91精品久久久久| 国产精品自在线| 96sao精品视频在线观看| 日韩视频在线免费观看| 久久精品国产欧美亚洲人人爽| 国产v综合v亚洲欧美久久| 亚洲成人av中文字幕| 91高清视频在线免费观看| 亚洲香蕉伊综合在人在线视看| 九九热视频这里只有精品| 黄色一区二区在线观看| 色噜噜狠狠狠综合曰曰曰| 日本精品视频在线观看| 91久久精品日日躁夜夜躁国产| 日韩av免费在线观看| 国产日韩欧美综合| 日韩欧美国产激情| 国产欧美日韩精品丝袜高跟鞋| 55夜色66夜色国产精品视频| 欧美xxxx做受欧美| 亚洲美女av网站| 亚洲国产欧美一区二区三区同亚洲| 亚洲欧美国产日韩中文字幕| 国产精品视频资源| 精品一区二区三区四区| 亚洲欧美日韩久久久久久| 亚洲第一av网站| 青青草精品毛片| 韩剧1988在线观看免费完整版| 亚洲va久久久噜噜噜久久天堂| 国产亚洲精品一区二区| 国产精品久久久久久久久久三级| 久久精品国产亚洲一区二区| 91香蕉国产在线观看| 亚洲最大中文字幕| 欧美精品18videos性欧美| 青草青草久热精品视频在线观看| 亚洲欧美激情在线视频| 日韩成人黄色av| 日韩大陆欧美高清视频区| 精品国产精品自拍| 国产精品视频最多的网站| 2019中文字幕全在线观看| 亚洲欧美日韩另类| 久热精品视频在线观看| 精品福利在线视频| 欧美成人四级hd版| 亚洲黄页视频免费观看| 亚洲美女自拍视频| 日韩黄色av网站| 欧美整片在线观看| 国产激情999| 中文字幕无线精品亚洲乱码一区| 最好看的2019的中文字幕视频| 狠狠综合久久av一区二区小说| 久久久国产影院| 一区二区三区 在线观看视| 中文字幕国产日韩| 国产欧美精品一区二区三区介绍| 久久精品国产亚洲一区二区| 国产精品白嫩初高中害羞小美女| 日韩欧美在线一区| 久久精品在线视频| 久久国产精品偷| 国产丝袜精品视频| 精品国产电影一区| 欧美黄色免费网站| 日韩三级影视基地| 亚洲自拍在线观看| 久久久国产精品x99av| 精品动漫一区二区三区| 国产91精品久久久久| 国产精品老女人视频| 在线视频免费一区二区| 欧美在线视频一区| 国产成人自拍视频在线观看| 日韩国产激情在线| 欧美性xxxxxx| 一区二区三区美女xx视频| 68精品久久久久久欧美| 欧美成人精品一区二区三区| 神马久久久久久| 8x海外华人永久免费日韩内陆视频| 亚洲欧洲午夜一线一品| 久久偷看各类女兵18女厕嘘嘘| 国产成人一区二区在线| 国产在线98福利播放视频| 久久久免费精品| 一区二区三区回区在观看免费视频| 久久免费国产精品1| 丰满岳妇乱一区二区三区| 欧美成人免费网| 国产精品久久99久久| 国产精品高精视频免费| 国产精品亚洲精品| 久久99精品久久久久久噜噜| 亚洲欧美日韩中文在线制服| 日本精品va在线观看| 日韩亚洲欧美成人| 久久99国产综合精品女同| 亚洲欧洲美洲在线综合| 国产剧情日韩欧美| 91亚洲va在线va天堂va国| 亚洲女人天堂色在线7777| 亚洲xxxxx电影| 国产精品一区二区久久久| 国产成人精品电影久久久| 国产一区二区三区在线观看网站| 7m精品福利视频导航| 亚洲人在线视频| 欧美精品在线第一页|