2009-05-28 6 views
0

J'ai deux tables liées dans ma base de données: Page et Tag. Une page peut être liée à plusieurs tags. Chaque fois qu'une de ces deux tables est modifiée, une procédure stockée appelée BeforePageHierarchyUpdate doit être exécutée (dans mon cas, cette procédure stockée effectue une journalisation et un contrôle de version sur la hiérarchie de page).Comment exécuter une procédure stockée une fois par mise à jour de la hiérarchie de classe dans LINQ?

Ce qui me donne des problèmes sont ces deux exigences:

  1. Le SP doit être exécuté si l'une instance de page ou une instance de balise sont mis à jour. Mais si une page ET l'une de ses étiquettes associées sont mises à jour, le fournisseur de service ne doit être appelé qu'une seule fois.

  2. La procédure stockée doit être contenue dans la même transaction que les autres instructions LINQ. Si les instructions LINQ échouent, la procédure stockée doit être annulée. Si la procédure stockée échoue, les instructions LINQ ne doivent pas être exécutées.

Est-ce que quelqu'un a des idées sur la façon de mettre en œuvre quelque chose comme ça?

Répondre

0

Après avoir creusé par un code, est une autre alternative ici. Je ne suis pas tout à fait à l'aise avec le fait que le code de connexion/transaction est correct (il a été principalement modifié à partir de l'implémentation de base de 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

Pour le meilleur ou pour le pire, c'est l'implémentation que j'utilise actuellement. Si je change d'avis, je vais essayer de me souvenir de mettre à jour cette question. – AaronSieb

0

ne met à jour ces tableaux en utilisant la procédure suivante:

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

Et si j'ai besoin de mettre à jour plusieurs Tags associés à une seule page? – AaronSieb

+0

passer dans une chaîne "tableau" (liste séparée par des virgules) et le diviser dans la procédure stockée: http://www.sommarskog.se/arrays-in-sql.html, j'aime cette méthode: http: // www.sommarskog.se/arrays-in-sql-2005.html#tblnum, vous pouvez diviser plusieurs paramètres dans SELECT FROM d'un INSERT dans une table temporaire, puis travailler avec des ensembles à partir de là. vous pouvez poser une autre question sur l'utilisation de plusieurs paramètres de liste séparés par des virgules et obtenir beaucoup d'informations à ce sujet. –

+0

Comment cela serait-il implémenté en utilisant le suivi des modifications de LINQ? Ou devra-t-il être appelé explicitement? – AaronSieb

0

Une troisième solution potentielle consiste à le placer dans la classe de référentiel (ou dans une autre implémentation d'encapsulation). Cela simplifie un peu le code de transaction, mais la fonctionnalité semble plus appropriée dans la couche 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); 
     } 
    } 
} 
Questions connexes