2009-05-28 28 views
0

我的數據庫中有兩個相關的表格:Page和Tag。一個頁面可以與許多標籤相關聯。如何在LINQ中的每個類層次結構更新中運行一次存儲過程?

無論何時修改這兩個表中的任何一個,需要執行一個名爲BeforePageHierarchyUpdate的存儲過程(在我的例子中,這個存儲過程在Page層次結構上執行一些日誌記錄和版本控制)。

什麼給我的問題是這兩個要求:

  1. 如果任一頁面實例或標記實例被更新的SP必須運行。但是,如果同時更新頁面及其相關標籤之一,則應僅調用SP一次。

  2. 存儲過程必須包含在與其他LINQ語句相同的事務中。如果LINQ語句失敗,則需要回滾存儲過程。如果存儲過程失敗,則不得執行LINQ語句。

有沒有人有任何想法如何實現這樣的事情?

回答

0

一些代碼挖後,這裏是另一種選擇。連接/事務代碼是正確的(我大部分是基於SubmitChanges實現的逆向工程),我並不完全確定。

public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode) { 
    if (System.Transactions.Transaction.Current == null && this.Transaction == null) { 
     bool connectionOpened = false; 
     DbTransaction transaction = null; 
     try { 
      if (this.Connection.State == ConnectionState.Closed) { 
       this.Connection.Open(); 
       connectionOpened = true; 
      } 
      transaction = this.Connection.BeginTransaction(IsolationLevel.ReadCommitted); 
      this.Transaction = transaction; 

      BeforeSubmitChanges(); 
      base.SubmitChanges(failureMode); 

      transaction.Commit(); 
     } 
     catch { 
      if (transaction != null) { 
       try { 
        transaction.Rollback(); 
       } 
       catch { 
       } 
       throw; 
      } 
     } 
     finally { 
      this.Transaction = null; 
      if (connectionOpened) { 
       this.Connection.Close(); 
      } 
     } 
    } 
    else { 
     BeforeSubmitChanges(); 
     base.SubmitChanges(failureMode); 
    } 
} 

private void BeforeSubmitChanges() { 
    ChangeSet changes = this.GetChangeSet(); 
    HashSet<int> modifiedPages = new HashSet<int>(); 

    foreach (Page page in changes.Updates.OfType<Page>()) { 
     modifiedPages.Add(page.PageId); 
    } 

    foreach(PageTag tag in changes.Updates.OfType<PageTag>()) { 
     modifiedPages.Add(tag.PageId); 
    } 

    foreach (PageTag tag in changes.Inserts.OfType<PageTag>()) { 
     //If the parent is being inserted, don't run the Update SP. 
     if (!changes.Inserts.Contains(tag.Page)) { 
      modifiedPages.Add(tag.PageId); 
     } 
    } 

    foreach (PageTag tag in changes.Deletes.OfType<PageTag>()) { 
     //If the parent is being deleted, don't run the Update SP. 
     if (!changes.Deletes.Contains(tag.Page)) { 
      modifiedPages.Add(tag.PageId); 
     } 
    } 

    foreach (int pageId in modifiedPages) { 
     this.BeforePageHierarchyUpdate(pageId); 
    } 
} 
0

僅使用以下步驟更新這些表:

create procedure UpdatePageAndOrTag 
(
    @mode    char(1) --"P"=page only, "T"=tag only, "B"=both 
    ,@pageParam1 ... 
    ,@pageParam2 .... 
    .... 
    ,@TagParam1..... 
    ,@TagParam2.... 
    .... 
) 

as 

EXEC BeforePageHierarchyUpdate 

if @Mode="B" or @Mode="P" 
Begin 
    update Page.... 
END 

IF @Mode="B" or @Mode="T" 
Begin 
    update tag... 
END 

return 0 
go 
+0

如果我需要更新與單個頁面關聯的多個標籤,該怎麼辦? – AaronSieb 2009-05-28 01:57:14

+0

傳遞一個「數組」(逗號分隔列表)字符串,並將其拆分到存儲過程中:http://www.sommarskog.se/arrays-in-sql.html,我喜歡這種方法:http:// www.sommarskog.se/arrays-in-sql-2005.html#tblnum,您可以將INSERT的SELECT FROM中的多個參數拆分爲臨時表,然後使用這些集合進行處理。你可以問另一個關於使用多個逗號分隔列表參數的問題,並獲得大量的信息。 – 2009-05-28 02:36:23

0

第三種可能的解決方案是將其放入存儲庫類(或其他包裝實現)中。這簡化了事務代碼,但在DataContext層中,這種功能感覺更合適。

public class PageRepository : IPageRepository { 
    public void Save() { 
     using(TransactionScope trans = new TransactionScope()) { 
      BeforeSubmitChanges(); 
      mDataContext.SubmitChanges(); 
      trans.Complete(); 
     } 
    } 

    private void BeforeSubmitChanges() { 
     ChangeSet changes = this.GetChangeSet(); 
     HashSet<int> modifiedPages = new HashSet<int>(); 

     foreach (Page page in changes.Updates.OfType<Page>()) { 
      modifiedPages.Add(page.PageId); 
     } 

     foreach(PageTag tag in changes.Updates.OfType<PageTag>()) { 
      modifiedPages.Add(tag.PageId); 
     } 

     foreach (PageTag tag in changes.Inserts.OfType<PageTag>()) { 
      //If the parent is being inserted, don't run the Update SP. 
      if (!changes.Inserts.Contains(tag.Page)) { 
       modifiedPages.Add(tag.PageId); 
      } 
     } 

     foreach (PageTag tag in changes.Deletes.OfType<PageTag>()) { 
      //If the parent is being deleted, don't run the Update SP. 
      if (!changes.Deletes.Contains(tag.Page)) { 
       modifiedPages.Add(tag.PageId); 
      } 
     } 

     foreach (int pageId in modifiedPages) { 
      this.BeforePageHierarchyUpdate(pageId); 
     } 
    } 
}