您将如何从业务逻辑层中的一种方法在数据访问层中调用几种方法,以使所有SQL命令都驻留在一个SQL事务中?
可以从BLL中的其他位置分别调用每个DAL方法,因此不能保证数据层方法始终是事务的一部分。我们需要此功能,因此,如果数据库在长时间运行的过程中脱机,则不会提交任何内容。业务层基于每个先前调用的结果来编排不同的数据层方法调用。我们只想在整个过程的最后(从业务层)提交。
好吧,首先,您必须遵守在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; }
希望你能得到要点。基本上,这是一个成功或失败的工作,而不管任何不同的数据库如何(例如,在上面的示例中,artist和artistartistgenre可以托管在两个单独的数据库存储中,但是TransactionScope不会在乎这一点,它可以在COM +级别工作并管理原子性可以“看到”的范围)
希望这可以帮助
编辑: 您可能会发现TransactionScope的初始调用(在应用程序启动时)可能会稍微引起注意(即,在上面的示例中,如果是第一次调用,则可能需要2-3秒才能完成),但是,随后的通话 几乎是 瞬时的(即通常为250-750毫秒)。在简单的联系点交易与(笨拙的)替代方案之间进行权衡,可以减轻(对我和我的客户而言)最初的“加载”延迟。
只是想证明轻松并非没有妥协(尽管在初始阶段)