2009-05-28 9 views
0

Ich habe zwei verwandte Tabellen in meiner Datenbank: Page und Tag. Eine Seite kann mit vielen Tags in Verbindung gebracht werden.Wie führe ich eine gespeicherte Prozedur einmal pro Klassenhierarchie-Update in LINQ aus?

Immer wenn eine dieser beiden Tabellen geändert wird, muss eine gespeicherte Prozedur namens BeforePageHierarchyUpdate ausgeführt werden (in meinem Fall führt diese gespeicherte Prozedur einige Protokollierung und Versionierung in der Page-Hierarchie durch).

Was mir Probleme hat zu geben sind diese beiden Anforderungen:

  1. Die SP ausgeführt werden muss, wenn entweder eine Page-Instanz oder eine Tag-Instanz aktualisiert werden. Wenn jedoch BEIDE Seiten und einer der zugehörigen Tags aktualisiert werden, sollte der SP nur einmal aufgerufen werden.

  2. Die gespeicherte Prozedur muss in derselben Transaktion wie die anderen LINQ-Anweisungen enthalten sein. Wenn die LINQ-Anweisungen fehlschlagen, muss die gespeicherte Prozedur zurückgesetzt werden. Wenn die gespeicherte Prozedur fehlschlägt, dürfen die LINQ-Anweisungen nicht ausgeführt werden.

Hat jemand irgendwelche Ideen, wie man so etwas implementiert?

Antwort

0

Nachdem durch einige Code zu graben, hier eine weitere Alternative ist. Ich bin nicht völlig sicher, dass der Verbindungs-/Transaktionscode korrekt ist (er wurde hauptsächlich von der SubmitChanges-Basisimplementierung revers entwickelt).

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

Für besser oder schlechter, das ist die Implementierung, die ich derzeit verwende. Wenn ich meine Meinung ändere, werde ich versuchen, mich daran zu erinnern, diese Frage zu aktualisieren. – AaronSieb

0

aktualisieren nur diese Tabellen mit dem folgenden Verfahren:

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

Was passiert, wenn ich mehrere Tags aktualisieren muss, die einer einzelnen Seite zugeordnet sind? – AaronSieb

+0

übergeben Sie eine "Array" (kommaseparierte Liste) Zeichenfolge und teilen Sie es in der gespeicherten Prozedur: http://www.sommarskog.se/arrays-in-sql.html, ich mag diese Methode: http: // www.sommarskog.se/arrays-in-sql-2005.html#tblnum, Sie können mehrere Parameter im SELECT FROM eines INSERT in eine temporäre Tabelle aufteilen und dann mit den Sets von dort arbeiten. Sie können eine weitere Frage zum Arbeiten mit mehreren durch Kommas getrennten Listenparametern stellen und erhalten viele Informationen dazu. –

+0

Wie würde dies mithilfe von LINQs Änderungsverfolgung implementiert werden? Oder muss es explizit genannt werden? – AaronSieb

0

Eine dritte mögliche Lösung besteht darin, sie in die Repository-Klasse (oder eine andere Wrapping-Implementierung) zu stellen. Dies vereinfacht den Transaktionscode erheblich, aber die Funktionalität fühlt sich in der DataContext-Schicht besser an.

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); 
     } 
    } 
} 
Verwandte Themen