Как запустить хранимую процедуру один раз для обновления иерархии классов в LINQ? - PullRequest
0 голосов
/ 28 мая 2009

У меня есть две связанные таблицы в моей базе данных: Page и Tag. Одна страница может быть связана со многими тегами.

Когда бы ни изменялась любая из этих двух таблиц, необходимо выполнять хранимую процедуру BeforePageHierarchyUpdate (в моем случае эта хранимая процедура выполняет некоторые записи в журнал и управление версиями в иерархии страницы).

Что вызывает у меня проблемы, это два требования:

  1. SP должен быть запущен, если обновляется либо экземпляр страницы, либо экземпляр тега. Но если ОБА и страница, и один из связанных с ней тегов обновляются, то SP следует вызывать только один раз.

  2. Хранимая процедура должна содержаться в той же транзакции, что и другие операторы LINQ. Если операторы LINQ не выполняются, хранимую процедуру необходимо откатить. В случае сбоя хранимой процедуры операторы LINQ не должны выполняться.

У кого-нибудь есть идеи, как реализовать что-то подобное?

Ответы [ 3 ]

0 голосов
/ 28 мая 2009

После копания некоторого кода, вот еще один вариант. Мне не совсем удобно, что код соединения / транзакции правильный (в основном это был обратный проект из базовой реализации 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 голосов
/ 28 мая 2009

Третье потенциальное решение - поместить его в класс репозитория (или другую реализацию обертки). Это немного упрощает код транзакции, но функциональность кажется более подходящей в слое 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);
        }
    }
}
0 голосов
/ 28 мая 2009

обновлять только эти таблицы, используя следующую процедуру:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...