2012-06-29 46 views
0

我有以下存儲庫。我有LINQ 2 SQL生成的類和使用工廠的域對象之間的映射。優化存儲庫的SubmitChanges方法

下面的代碼將工作;但我看到兩個潛在的問題

1)它正在更新語句之前使用SELECT查詢。

2)它需要更新所有列(不僅僅是更改的列)。這是因爲我們不知道域對象中的所有列都被更改了。

如何克服這些缺點?

注意:可能會有一些情景(如觸發器)根據特定的列更新執行。所以我無法不必要地更新一列。

REFERENCE

  1. LINQ to SQL: Updating without Refresh when 「UpdateCheck = Never」

  2. http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=113917

CODE

namespace RepositoryLayer 
{ 
public interface ILijosBankRepository 
{  
    void SubmitChangesForEntity(); 
} 

public class LijosSimpleBankRepository : ILijosBankRepository 
{ 

    private IBankAccountFactory bankFactory = new MySimpleBankAccountFactory(); 
    public System.Data.Linq.DataContext Context 
    { 
     get; 
     set; 
    } 


    public virtual void SubmitChangesForEntity(DomainEntitiesForBank.IBankAccount iBankAcc) 
    { 
     //Does not get help from automated change tracking (due to mapping) 

     //Selecting the required entity 
     DBML_Project.BankAccount tableEntity = Context.GetTable<DBML_Project.BankAccount>().SingleOrDefault(p => p.BankAccountID == iBankAcc.BankAccountID); 

     if (tableEntity != null) 
     { 
      //Setting all the values to updates (except primary key) 
      tableEntity.Status = iBankAcc.AccountStatus; 

      //Type Checking 
      if (iBankAcc is DomainEntitiesForBank.FixedBankAccount) 
      { 
       tableEntity.AccountType = "Fixed"; 
      } 

      if (iBankAcc is DomainEntitiesForBank.SavingsBankAccount) 
      { 
       tableEntity.AccountType = "Savings"; 
      } 

      Context.SubmitChanges(); 
     } 
    } 
} 

} 

namespace DomainEntitiesForBank 
{ 

public interface IBankAccount 
{ 
    int BankAccountID { get; set; } 
    double Balance { get; set; } 
    string AccountStatus { get; set; } 
    void FreezeAccount(); 

} 

public class FixedBankAccount : IBankAccount 
{ 

    public int BankAccountID { get; set; } 
    public string AccountStatus { get; set; } 
    public double Balance { get; set; } 

    public void FreezeAccount() 
    { 
     AccountStatus = "Frozen"; 
    } 
} 


} 
+0

「這需要更新所有列」。這是什麼性能打擊?你有沒有測量過這個? – Steven

+0

@Steven這是我的假設。畢竟,這是一種不必要的努力 - 在邏輯上。從SQL的角度來看,可能並非如此。此外,可能會有一些情景(如觸發器)根據列更新執行。所以我無法不必要地更新一列。 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=113917 – Lijo

+0

除非你「繼承」數據庫的設計,我覺得你真的不得不重新考慮這種使用觸發器。如果您只是因爲記錄更改而需要觸發,請在表中使用時間戳,並讓您的更新觸發器對此進行響應。 – Pleun

回答

1

如果我理解你的問題,你正在傳遞,你需要保存到數據庫中不知道什麼原始值是一個實體,或列的實際變化。

如果是這樣的話,那麼你有四個選項

  1. 你需要去回數據庫,查看原始值,即進行選擇,因爲你的代碼在做什麼。這使您可以設置所有的實體值,Linq2Sql將負責實際更改哪些列。所以如果你的列沒有實際改變,那麼沒有更新語句被觸發。

  2. 你需要避免的選擇,只是更新列。你已經知道該怎麼做(但對於其他人,請參閱this question and answer)。由於您不知道哪些列已更改,因此您無法將其全部設置。這將產生一個更新語句,即使沒有實際更改列,這可以觸發任何數據庫觸發器。除了禁用觸發器,你可以在這裏做的唯一的事情是確保觸發器被寫入檢查新舊列中的值,以避免任何進一步的不必要的更新。

  3. 您需要更改您的要求/程序,以便您需要的新舊和實體值,因此可以判斷哪些列,而不必返回到數據庫中已經改變。

  4. 不要使用LINQ爲您更新。 LINQ代表語言集成查詢它是(恕我直言)輝煌的查詢,但我總是看更新/刪除功能作爲額外的獎勵,但不是它的目的。另外,如果時序/性能至關重要,那麼LINQ將無法正確匹配手工製作的SQL。

+0

謝謝。有關選項#2的問題。如果我直接使用生成的實體作爲域類(沒有使用手動編寫的域類進行映射),我可以只更新所需的列而不選擇。這將滿足這個問題的兩個要求。你看到這種方法有什麼缺點嗎? – Lijo

1

這不是一個真正的DDD問題;從我可以告訴你,都在問:

Use linq to generate direct update without select

凡接受的答案是沒有它不可能,但那裏有更高的投票的回答表明您可以附加對象對上下文啓動數據上下文的更改跟蹤。

關於禁用觸發器的第二點已經回答了herehere。但正如其他人所評論的,你是否真的需要觸發器?你不應該在代碼中控制這些更新嗎?

一般來說,我認爲你正在尋找不成熟的優化。您正在使用ORM,並將其作爲您在L2S中信任的一部分,以便爲您做數據庫管理決策。但要記得在適當的時候可以使用存儲過程執行特定的SQL。