ну, во-первых, вам нужно будет придерживаться атомарной единицы работы, которую вы указываете как отдельный метод в своем 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 мс). компромисс между простой транзакцией точки контакта и (громоздкими) альтернативами уменьшает (для меня и моих клиентов) эту первоначальную задержку загрузки.
просто хотел продемонстрировать, что легкость не приходит без компромиссов (хотя и на начальных этапах)