小編給大家分享一下EntityFramework 6.x中多個上下文遷移如何實現(xiàn)分布式事務,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
站在用戶的角度思考問題,與客戶深入溝通,找到襄陽網(wǎng)站設(shè)計與襄陽網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、空間域名、網(wǎng)站空間、企業(yè)郵箱。業(yè)務覆蓋襄陽地區(qū)。模型建立
在開始EntityFramework 6.x內(nèi)容敘述之前,我們還是老套路,首先準備模型,我們搞一個預約航班的基本模型,一個是航班實體,另外一個為預約實體,請看如下:
/// <summary> /// 航班 /// </summary> public class FlightBooking { /// <summary> /// 航班Id /// </summary> public int FlightId { get; set; } /// <summary> /// 航班名稱 /// </summary> public string FilghtName { get; set; } /// <summary> /// 航班號 /// </summary> public string Number { get; set; } /// <summary> /// 出行日期 /// </summary> public DateTime TravellingDate { get; set; } }
/// <summary> /// 預訂 /// </summary> public class Reservation { /// <summary> /// 預訂Id /// </summary> public int BookingId { get; set; } /// <summary> /// 預訂人 /// </summary> public string Name { get; set; } /// <summary> /// 預訂日期 /// </summary> public DateTime BookingDate { get; set; } = DateTime.Now; }
public class TripReservation { public FlightBooking Filght { get; set; } public Reservation Hotel { get; set; } }
此類用于維護航班和預約的實體,在創(chuàng)建預約航班時使用。在EntityFramework 6.0+版本上出現(xiàn)了基于代碼配置(Code-based Configuration),對于數(shù)據(jù)庫初始化策略和其他等等配置,我們單獨建立一個配置類來維護,而無需如我們以往一樣放在DbContext上下文派生類構(gòu)造函數(shù)中,這樣一來上下文派生類看起來則潔凈很多。
public class HotelFlightConfiguration : DbConfiguration { public HotelFlightConfiguration() { SetDatabaseInitializer(new DropCreateDatabaseIfModelChanges<HotelDBContext>()); SetDatabaseInitializer(new DropCreateDatabaseIfModelChanges<FlightDBContext>()); } }
接下來我們再來配置兩個DbContext上下文派生類即HotelDbContext和FlightDbContext,并且基本配置信息利用特性來修飾,如下:
[DbConfigurationType(typeof(HotelFlightConfiguration))] public class FlightDBContext : DbContext { public FlightDBContext() : base("name=flightConnection") { } public DbSet<FlightBooking> FlightBookings { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new FlightBookingMap()); base.OnModelCreating(modelBuilder); } }
[DbConfigurationType(typeof(HotelFlightConfiguration))] public class HotelDBContext: DbContext { public HotelDBContext():base("name=reservationConnction") { } public DbSet<Reservation> Reservations { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new ReservationMap()); base.OnModelCreating(modelBuilder); } }
對應的映射配置已經(jīng)敘述很多次了,我們不用廢話,直接給出。
public class FlightBookingMap : EntityTypeConfiguration<FlightBooking> { public FlightBookingMap() { //table ToTable("FlightBookings"); //key HasKey(k => k.FlightId); //property Property(p => p.FilghtName).HasMaxLength(50); Property(p => p.Number); Property(p => p.TravellingDate); } }
public class ReservationMap : EntityTypeConfiguration<Reservation> { public ReservationMap() { //table ToTable("Reservations"); //key HasKey(k => k.BookingId); //property Property(p => p.BookingId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); Property(p => p.Name).HasMaxLength(20); Property(p => p.BookingDate); } }
如上兩個上下文我們將遷移到不同數(shù)據(jù)庫,所以連接字符串當然是兩個啦。
<connectionStrings> <add name="reservationConnction" connectionString="Data Source=WANGPENG;Initial Catalog=ReservationDb;Integrated Security=true" providerName="System.Data.SqlClient" /> <add name="flightConnection" connectionString="Data Source=WANGPENG;Initial Catalog=FlightDb;Integrated Security=true" providerName="System.Data.SqlClient" /> </connectionStrings>
好了,模型和上下文一切都已構(gòu)建完畢,接下來進入到遷移,請往下看。
多個上下文遷移
一個上下文進行遷移已經(jīng)沒有什么可說的了,在大多數(shù)場景下,貌似都是一個應用程序中僅僅存在一個上下文,因為幕后對應的只有一個數(shù)據(jù)庫,這個大家是手到擒來,而對于多個上下文遷移對應不同數(shù)據(jù)庫遷移又怎么去操作呢?如果你非常熟悉遷移命令,那么就當做是回顧吧,如若不然,可以此作為基本參考,有點啰嗦了哈,我們進入正文。將模型遷移至數(shù)據(jù)庫并持久化只需要如下三步。
多個上下文遷移至不同文件夾目錄
Enable-Migrations命令
Add-Migration命令
Update-database命令
當統(tǒng)一應用程序只存在一個上下文時,我們只需要Enabel-Migrations即可,但是若存在多個上下文,若不明確指定上下文很顯然會遷移報錯,首先我們在NuGet控制臺將項目更換到上下文所在項目中。
接下來運行Enable-Migrations初始化遷移目錄,很明顯會出現(xiàn)遷移異常。
由于存在多個上下文,所以我們需要明確指定遷移哪個上下文。通過在其命令后繼續(xù)添加-ContextTypeName指定上下文,并繼續(xù)利用-MigrtionsDirectory指定遷移目錄,最后則是如下命令(不知道有哪些命令嗎,在每個命令后添加一個【-】橫桿并按下Tab鍵則出現(xiàn)你想要的命令)。
Enable-Migrations -ContextTypeName FlightDbContext -MigrationsDirectory:FlightMigrations
接下來利用Add-Migration命令對已掛起模型改變搭建基架,也就是說將上次遷移后我們對模型發(fā)生了更改,以此為下一次遷移搭建基架,此時生成的模型狀態(tài)為掛起狀態(tài)或者稱作為待定狀態(tài)。我們需要遷移上述生成FlightMigrations目錄下的Configuration類,所以此時在Add-Migration命令后指定-ConfigurationTypeName,然后通過-Name指定第一次基架名稱。
Add-Migration -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration -Name Initial
或者
Add-Migration -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration "Initial"
最后則只需要通過Update-database來持久化到數(shù)據(jù)庫生成表了。
Update-Database -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration
同理我們對HotelDbContext利用上述三步命令來進行遷移,最后我們能夠很清晰的看到,每個上下文遷移在不同目錄,如下:
上述遷移也沒任何毛病,將每個上下文單獨遷移生成文件夾,那么我們是否有想過將多個上下文遷移到同一目錄文件夾下且區(qū)分開來呢,在我們只有一個上下文時默認給我們創(chuàng)建的文件夾為Migrations,我們就在Migrtions文件夾下生成不同上下文遷移配置。
多個上下文遷移至相同文件夾目錄
這個其實也很簡單,我們在-MigrationDirectoty后面可以直接指定某個文件夾生成上下文,例如C:\A\DbContext,EntityFramework也做到了這點,下面我們來看看。
Enable-Migrations -ContextTypeName FlightDbContext -MigrationsDirectory Migrations\FlightDbContext
Enable-Migrations -ContextTypeName HotelDbContext -MigrationsDirectory Migrations\HotelDbContext
其余兩步運行方式和遷移不同一樣,最終我們會看到想要的結(jié)果。
通過上述遷移最終將生成FlightDb和ReservationDb兩個數(shù)據(jù)庫并對應FlightBookings和Reservations表。好了到此關(guān)于多個上下文遷移兩種方式就結(jié)束了,我們繼續(xù)本節(jié)的話題。
分布式事務
有時候我們需要跨數(shù)據(jù)庫管理事務,例如有這樣一個場景,有兩個數(shù)據(jù)庫db1和db2,而tb1在db1中,tb2在db2中,同時tb1和tb2是關(guān)聯(lián)的,在上述中我們創(chuàng)建的航班和預訂模型,我們需要同時插入航班數(shù)據(jù)和預約數(shù)據(jù)到不同數(shù)據(jù)庫中,此時則要求事務一致性,所以為了處理這樣的要求,在.NET 2.0,在System.Transaction命名空間下為我們提供了TransactionScope類。 此類提供了一種使代碼塊參與事務而不需要與事務本身交互的簡單方式。強烈建議在using塊中創(chuàng)建TransactionScope對象。
當TransactionScope被實例化時,事務管理器需要確定要參與哪個事務。一旦確定,該實例將一直參與到事務中。 在創(chuàng)建TransactionScope對象時,我們需要傳遞具有以下值的TransactionScopeOption枚舉:
Required:實例必須需要事務,如果事務已存在,則使用已存在事務,否則將創(chuàng)建新事務。
RequiresNew:始終為實例創(chuàng)建一個新的事務。
Suppress:創(chuàng)建實例時,其他已存在事務將被抑制,因為該實例內(nèi)的所有操作的完成而無需其他已存在事務。
接下來我們利用上述枚舉中第二種方式來實現(xiàn)航班預約,簡單邏輯如下:
public class MakeReservation { FlightDBContext flight; HotelDBContext hotel; public MakeReservation() { flight = new FlightDBContext(); hotel = new HotelDBContext(); } //處理事務方法 public bool ReservTrip(TripReservation trip) { bool reserved = false; //綁定處理事務范圍 using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { //航班信息 flight.FlightBookings.Add(trip.Filght); flight.SaveChanges(); //預約信息 hotel.Reservations.Add(trip.Hotel); hotel.SaveChanges(); reserved = true; //完成事務并提交 scope.Complete(); } catch (Exception ex) { throw ex; } } return reserved; } }
上述ReservTrip方法接受TripReservation對象。 該方法定義了TransactionScope,并在事務的上下文中捆綁了用于Flight和Hotel的Create操作,并將代碼寫入try-catch塊中。 如果兩個實體的SaveChanges方法成功執(zhí)行,那么事務將被完成,否則回滾。接下來進行控制器調(diào)用。
public class TripController : Controller { MakeReservation reserv; public TripController() { reserv = new MakeReservation(); } public ActionResult Index() { return View(); } public ActionResult Create() { return View(new TripReservation()); } [HttpPost] public ActionResult Create(TripReservation tripinfo) { try { tripinfo.Filght.TravellingDate = DateTime.Now; tripinfo.Hotel.BookingDate = DateTime.Now; var res = reserv.ReservTrip(tripinfo); if (!res) { return View("Error"); } } catch (Exception) { return View("Error"); } return View("Success"); } }
我們添加航班預約視圖:
@model EntityFrameworkTransactionScope.Data.Entity.TripReservation @{ ViewBag.Title = "Create"; } <h3 class="text-center">旅游出行</h3> @using(Html.BeginForm()){ <table class="table table-condensed table-striped table-bordered"> <tr> <td> <table class="table table-condensed table-striped table-bordered"> <tr> <td colspan="2" class="text-center"> 航班信息 </td> </tr> <tr> <td> 航班Id: </td> <td> @Html.EditorFor(m => m.Filght.FlightId) </td> </tr> <tr> <td> 航班名稱: </td> <td> @Html.EditorFor(m => m.Filght.FilghtName) </td> </tr> <tr> <td> 航班號: </td> <td> @Html.EditorFor(m => m.Filght.Number) </td> </tr> </table> </td> <td> <table class="table table-condensed table-striped table-bordered"> <tr> <td colspan="2" class="text-center"> 預約信息 </td> </tr> <tr> <td> 預約Id: </td> <td> @Html.EditorFor(m => m.Hotel.BookingId) </td> </tr> <tr> <td> 客戶名稱 </td> <td> @Html.EditorFor(m => m.Hotel.Name) </td> </tr> </table> </td> </tr> <tr> <td colspan="2" class="text-center"> <input type="submit" value="提交預約" /> </td> </tr> </table> }
視圖展示UI如下:
要運行應用程序并檢查事務,我們需要使用分布式事務處理協(xié)調(diào)器(DTC)服務。 該服務協(xié)調(diào)更新兩個或多個事務受保護資源的事務,例如數(shù)據(jù)庫,消息隊列,文件系統(tǒng)等。首先我們需要確保DTC是否已經(jīng)開啟,在服務中進行查看并啟用。
接下來打開DTC設(shè)置,請按照下列步驟操作或者直接運行【dcomcnfg.exe】一步到位打開組件服務。
打開控制面板
找到管理工具
找到組件服務
接下來我們填寫相關(guān)信息來進行航班預約。
如上顯示已經(jīng)預約成功,我們看看兩個數(shù)據(jù)庫中的數(shù)據(jù)是否正確插入。
在DTC服務中,若每次提交未中止則提交數(shù)量將增加1,在我們對預約模型進行配置時,我們將主鍵未設(shè)置為標識列,所以在我們對主鍵重復的情況下再來看看表中數(shù)據(jù)。我們提交三次而預約主鍵不重復,在第四次時主鍵輸入為第三次的主鍵,此時看看結(jié)果如下:
我們驗證leFlightBookings和Reservations表中的數(shù)據(jù),則新添加的記錄將不會顯示在其中。 這意味著TransactionScope已經(jīng)通過在單個范圍中將連接與Flight和Hotel數(shù)據(jù)庫捆綁在一起來管理Transaction,并監(jiān)控了Committed和Aborted Transaction。
以上是“EntityFramework 6.x中多個上下文遷移如何實現(xiàn)分布式事務”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)頁名稱:EntityFramework6.x中多個上下文遷移如何實現(xiàn)分布式事務-創(chuàng)新互聯(lián)
文章地址:http://jinyejixie.com/article30/ghiso.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、靜態(tài)網(wǎng)站、企業(yè)網(wǎng)站制作、網(wǎng)站維護、云服務器、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)