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

BLL中的一种方法跨多种DAL方法的交易

  •  6
  • Dela  · 技术社区  · 16 年前

    您将如何从业务逻辑层中的一个方法调用数据访问层中的多个方法,以便所有SQL命令都存在于一个SQL事务中?

    每个DAL方法都可以从BLL中的其他位置单独调用,因此不能保证数据层方法始终是事务的一部分。我们需要这个功能,所以如果数据库在长时间运行的过程中离线,就没有提交。业务层正在根据前面每个调用的结果编排不同的数据层方法调用。我们只想在整个流程的最后提交(从业务层)。

    4 回复  |  直到 16 年前
        1
  •  8
  •   Tom H zenazn    15 年前

    首先,您必须遵守在BLL中指定为单个方法的原子工作单元。这将(例如)创建客户、订单和订单项。然后,您可以使用语句将这一切整齐地包装在TransactionScope中。TransactionScope是这里的秘密武器。下面是我现在正在编写的一些代码:):

    public static int InsertArtist(Artist artist)
    {
        if (artist == null)
            throw new ArgumentNullException("artist");
    
        int artistid = 0;
        using (TransactionScope scope = new TransactionScope())
        {
            // insert the master Artist
            /* 
               we plug the artistid variable into 
               any child instance where ArtistID is required
            */
            artistid = SiteProvider.Artist.InsertArtist(new ArtistDetails(
            0,
            artist.BandName,
            artist.DateAdded));
    
            // insert the child ArtistArtistGenre
            artist.ArtistArtistGenres.ForEach(item =>
            {
                var artistartistgenre = new ArtistArtistGenreDetails(
                    0,
                    artistid,
                    item.ArtistGenreID);
                SiteProvider.Artist.InsertArtistArtistGenre(artistartistgenre);
            });
    
            // insert the child ArtistLink
            artist.ArtistLinks.ForEach(item =>
            {
                var artistlink = new ArtistLinkDetails(
                    0,
                    artistid,
                    item.LinkURL);
                SiteProvider.Artist.InsertArtistLink(artistlink);
            });
    
            // insert the child ArtistProfile
            artist.ArtistProfiles.ForEach(item =>
            {
                var artistprofile = new ArtistProfileDetails(
                    0,
                    artistid,
                    item.Profile);
                SiteProvider.Artist.InsertArtistProfile(artistprofile);
            });
    
            // insert the child FestivalArtist
            artist.FestivalArtists.ForEach(item =>
            {
                var festivalartist = new FestivalArtistDetails(
                    0,
                    item.FestivalID,
                    artistid,
                    item.AvailableFromDate,
                    item.AvailableToDate,
                    item.DateAdded);
                SiteProvider.Festival.InsertFestivalArtist(festivalartist);
            });
            BizObject.PurgeCacheItems(String.Format(ARTISTARTISTGENRE_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTISTLINK_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTISTPROFILE_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(FESTIVALARTIST_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTIST_ALL_KEY, String.Empty, String.Empty));
    
            // commit the entire transaction - all or nothing
            scope.Complete();
        }
        return artistid;
    }
    

    希望你能明白要点。基本上,这是一项成败参半的工作,与任何不同的数据库无关(即在上面的例子中,艺术家和艺术家流派可以托管在两个单独的数据库存储中,但TransactionScope对此不太关心,它在COM+级别工作,并管理它可以“看到”的范围的原子性)

    希望这有帮助

    编辑: 您可能会发现,TransactionScope的初始调用(在应用程序启动时)可能有点明显(即在上面的示例中,如果是第一次调用,可能需要2-3秒才能完成),但是,后续调用是 几乎 瞬时(即通常为250-750ms)。简单的接触点事务与(笨拙的)替代方案之间的权衡减轻了(对我和我的客户来说)最初的“加载”延迟。

    只是想证明,轻松并非没有妥协(尽管是在初始阶段)

        2
  •  4
  •   user60400    16 年前

    你所描述的正是长期交易的“定义”。

    每个DAL方法都可以简单地提供操作(无需任何特定的提交)。您的BLL(实际上是您协调对DAL的任何调用的地方)是您可以选择提交或执行“保存点”的地方。保存点是一个可选项,您可以使用它来允许在长时间运行的事务中进行“回滚”。

    例如,如果我的DAL的DAL1、DAL2、DAL3方法都是变异的,它们只会“执行”数据更改操作(即某种类型的创建、更新、删除)。从我的BLL中,假设我有BL1和BL2方法(BL1长时间运行)。BL1调用所有上述DAL方法(即DAL1…DAL3),而BL2仅调用DAL3。

    因此,在执行每个业务逻辑方法时,您可能会遇到以下情况:

    BL1(长期交易)->{保存点}DAL1->{保存点}DAL2->DAL3{提交/结束}

    BL2->DAL3{提交/结束}

    “保存点”背后的想法是,如果数据操作中出现问题,它可以允许BL1在任何时候回滚。只有当所有三个操作都成功完成时,才会提交长期交易。BL2仍然可以调用DAL中的任何方法,并负责控制提交。注意:您也可以在短期/常规事务中使用“保存点”。

        3
  •  2
  •   dkretz    16 年前

    好问题。这触及了阻抗失配的核心。

    这是使用存储过程的最有力论据之一。原因:它们旨在将多个SQL语句封装在一个事务中。

    在DAL中也可以按程序进行同样的操作,但这会导致代码不太清晰,同时通常会导致耦合/内聚平衡朝着错误的方向移动。

    因此,我在比简单封装表更高的抽象级别上实现了DAL。

        4
  •  1
  •   lockNetMonster lockNetMonster    16 年前

    为了防止我在原始文章中的评论不“坚持”,以下是我添加的额外信息:

    <----- 巧合的是,我刚刚注意到在你的请求后几个小时又发布了一条类似的引用。使用类似的策略,可能也值得您考虑: http://stackoverflow.com/questions/494550/how-does-transactionscope-roll-back-transactions ----->