代码之家  ›  专栏  ›  技术社区  ›  AaronSieb

如何在LINQ中每个类层次结构更新一次运行存储过程?

  •  0
  • AaronSieb  · 技术社区  · 15 年前

    我的数据库中有两个相关的表:page和tag。一个页面可以与许多标记相关。

    每当修改这两个表中的任何一个时,都需要执行名为beforepagehierarchyupdate的存储过程(在我的示例中,此存储过程在页面层次结构上执行一些日志记录和版本控制)。

    给我带来问题的是这两个要求:

    1. 如果更新了页实例或标记实例,则必须运行sp。但是,如果一个页面和它的一个相关标记都被更新了,那么SP应该只被调用一次。

    2. 存储过程必须与其他LINQ语句包含在同一事务中。如果LINQ语句失败,则需要回滚存储过程。如果存储过程失败,则不能执行LINQ语句。

    有人对如何实现这样的东西有什么想法吗?

    3 回复  |  直到 15 年前
        1
  •  0
  •   racer x    15 年前

    仅使用以下过程更新这些表:

    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
    
        2
  •  0
  •   AaronSieb    15 年前

    在挖掘了一些代码之后,这里还有另一种选择。我对连接/事务代码的正确性并不完全满意(它主要是从基本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);
        }
    }
    
        3
  •  0
  •   AaronSieb    15 年前

    第三种可能的解决方案是将其放入知识库类(或其他包装实现)。这相当简化了事务代码,但在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);
            }
        }
    }