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

Linq to sql 如何在LINQ中每次类层次结构更新时运行一次存储过程?,linq-to-sql,Linq To Sql,我的数据库中有两个相关的表:Page和Tag。一个页面可以与多个标记相关 无论何时修改这两个表中的任何一个,都需要执行名为BeforePageHierarchyUpdate的存储过程(在我的例子中,该存储过程在页面层次结构上执行一些日志记录和版本控制) 给我带来问题的是这两个要求: 如果更新了页面实例或标记实例,则必须运行SP。但是,如果一个页面及其一个相关标记都被更新,则SP应该只被调用一次 存储过程必须包含在与其他LINQ语句相同的事务中。如果LINQ语句失败,则需要回滚存储过程。如果存储过

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

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

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

  • 如果更新了页面实例或标记实例,则必须运行SP。但是,如果一个页面及其一个相关标记都被更新,则SP应该只被调用一次

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


  • 有人对如何实现这样的功能有什么想法吗?

    仅使用以下步骤更新这些表:

    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
    

    在浏览了一些代码之后,这里是另一个选择。我对连接/事务代码是否正确并不完全满意(它大部分是从基本SubmitChanges实现反向工程的)

    公共覆盖无效提交更改(System.Data.Linq.ConflictMode故障模式){
    if(System.Transactions.Transaction.Current==null&&this.Transaction==null){
    bool connectionOpened=false;
    DbTransaction=null;
    试一试{
    if(this.Connection.State==ConnectionState.Closed){
    this.Connection.Open();
    连接开放=真;
    }
    事务=this.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
    这个。事务=事务;
    提交更改前();
    基本提交更改(故障模式);
    Commit();
    }
    抓住{
    if(事务!=null){
    试一试{
    transaction.Rollback();
    }
    抓住{
    }
    投
    }
    }
    最后{
    this.Transaction=null;
    如果(连接打开){
    this.Connection.Close();
    }
    }
    }
    否则{
    提交更改前();
    基本提交更改(故障模式);
    }
    }
    提交更改前的私有无效(){
    changesetchanges=this.GetChangeSet();
    HashSet modifiedpage=新HashSet();
    foreach(changes.Updates.OfType()中的页面){
    修改页面。添加(页面。页面ID);
    }
    foreach(changes.Updates.OfType()中的PageTag标记){
    modifiedpage.Add(tag.PageId);
    }
    foreach(changes.Inserts.OfType()中的PageTag标记){
    //如果要插入父级,请不要运行更新SP。
    如果(!changes.Inserts.Contains(tag.Page)){
    modifiedpage.Add(tag.PageId);
    }
    }
    foreach(changes.Deletes.OfType()中的PageTag标记){
    //如果要删除父级,请不要运行更新SP。
    如果(!changes.Deletes.Contains(tag.Page)){
    modifiedpage.Add(tag.PageId);
    }
    }
    foreach(修改页中的int pageId){
    此.BeforePageHierarchyUpdate(pageId);
    }
    }
    
    第三种可能的解决方案是将其放入repository类(或其他包装实现)中。这大大简化了事务代码,但该功能在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);
            }
        }
    }
    
    公共类页面存储库:IPageRepository{
    公共作废保存(){
    使用(TransactionScope trans=new TransactionScope()){
    提交更改前();
    mDataContext.SubmitChanges();
    trans.Complete();
    }
    }
    提交更改前的私有无效(){
    changesetchanges=this.GetChangeSet();
    HashSet modifiedpage=新HashSet();
    foreach(changes.Updates.OfType()中的页面){
    修改页面。添加(页面。页面ID);
    }
    foreach(changes.Updates.OfType()中的PageTag标记){
    modifiedpage.Add(tag.PageId);
    }
    foreach(changes.Inserts.OfType()中的PageTag标记){
    //如果要插入父级,请不要运行更新SP。
    如果(!changes.Inserts.Contains(tag.Page)){
    modifiedpage.Add(tag.PageId);
    }
    }
    foreach(changes.Deletes.OfType()中的PageTag标记){
    //如果要删除父级,请不要运行更新SP。
    如果(!changes.Deletes.Contains(tag.Page)){
    modifiedpage.Add(tag.PageId);
    }
    }
    foreach(修改页中的int pageId){
    此.BeforePageHierarchyUpdate(pageId);
    }
    }
    }
    
    如果我需要更新与单个页面相关联的多个标记,该怎么办?传入一个“数组”(逗号分隔列表)字符串并在存储过程中拆分它:,我喜欢这种方法:,您可以将插入的SELECT FROM中的多个参数拆分到临时表中,然后从中使用集合。你可以问另一个关于使用多个逗号分隔的列表参数的问题,并得到很多关于这方面的信息。如何使用LINQ的更改跟踪来实现这一点?还是必须显式地调用它?不管是好是坏,这是我目前正在使用的实现。如果我改变主意,我会尽量记住更新这个问题。
    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);
            }
        }
    }