EntityFramework 6.x learn how to implement distributed transactions through context migration. entityframework6.x

Source: Internet
Author: User
Tags connectionstrings

EntityFramework 6.x learn how to implement distributed transactions through context migration. entityframework6.x

Preface

Since the project. NET Core platform has used EntityFramework Core and has never touched EntityFramework 6. version x. Currently, EntityFramework 6. x is the most widely used. In terms of looking for a job or improving its own technology, it has its own benefits. At the same time, in addition to work, it still has a small amount of time to write EntityFramework 6. x and EntityFramework Core books, so the EntityFramework 6. x is equivalent to learning from scratch, EntityFramework 6. x has added many features, so it took some time to look at and sort them out. This section is equivalent to a problem that I have never encountered, so I spent a little time migrating multiple contexts to different databases and implementing distributed transactions. As a basic entry and synchronized to books, it is also a bit of accumulation for readers to learn. If there is an error in this article, please correct.

Model Creation

Start EntityFramework 6. before describing the content of x, we are still the old routine. First, we prepare a model to create a basic model for booking flights. One is the flight entity and the other is the booking entity. See the following for details:

/// <Summary> // flight // </summary> public class FlightBooking {// <summary> // flight Id /// </summary> public int FlightId {get; set ;}//< summary> /// flight name /// </summary> public string FilghtName {get; set ;} /// <summary> /// flight Number /// </summary> public string Number {get; set ;} /// <summary> // travel date // </summary> public DateTime TravellingDate {get; set ;}}
/// <Summary> /// Reservation /// </summary> public class Reservation {// <summary> /// Reservation Id /// </summary> public int BookingId {get; set ;}//< summary> /// reserved by /// </summary> public string Name {get; set ;} /// <summary> /// reservation date /// </summary> public DateTime BookingDate {get; set ;}= DateTime. now ;}
public class TripReservation {  public FlightBooking Filght { get; set; }  public Reservation Hotel { get; set; } }

This type of entity is used to maintain flights and reservations, and is used when booking flights are created. Code-based Configuration is displayed in EntityFramework 6.0 +. For database initialization policies and other configurations, we create a Configuration class for maintenance, instead of placing it in the constructor of the DbContext context derived class as before, the context derived class looks much cleaner.

public class HotelFlightConfiguration : DbConfiguration {  public HotelFlightConfiguration()  {      SetDatabaseInitializer(new DropCreateDatabaseIfModelChanges<HotelDBContext>());   SetDatabaseInitializer(new DropCreateDatabaseIfModelChanges<FlightDBContext>());  } }

Next, we will configure two DbContext context Derived classes: mongodbcontext and FlightDbContext. The basic configuration information is modified using the features, as shown below:

[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);  } }

The corresponding ing configuration has been described many times, so we don't need to talk about it.

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);  } }

The above two contexts will be migrated to different databases, so the connection string is of course two.

<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>

All right, the model and context have been built, and the next step is migration. Please refer to it.

Multi-context migration

There is nothing to say about migrating a context. In most scenarios, it seems that only one context exists in an application, because there is only one database behind the scenes, and everyone is here, how can we migrate different databases for multi-context migration? If you are very familiar with the migration command, let's review it. If not, it can be used as a basic reference. It's a bit awkward. Let's go to the text. To migrate the model to the database and make it persistent, you only need to perform the following three steps.

Migrate multiple contexts to different folder Directories

Enable-Migrations command

Add-Migration command

Update-database command

When a unified application only has one context, we only need Enabel-Migrations. However, if multiple contexts exist, if the context is not explicitly specified, it is clear that an error will be returned during migration, first, change the project to the project where the context is located in the NuGet console.

Next, run Enable-Migrations to initialize the migration directory. Obviously, a migration exception occurs.

Because there are multiple contexts, we need to specify which context to migrate. After the command is run, add "-ContextTypeName" to specify the context and use "-MigrtionsDirectory" to specify the migration directory. The command is as follows (Do you know which commands are available, add a [-] crossbar after each command and press the Tab key to display the command you want ).

Enable-Migrations -ContextTypeName FlightDbContext -MigrationsDirectory:FlightMigrations

Next, we will use the Add-Migration command to build a baseline for a pending model change. That is to say, we have changed the model after the last Migration to build the baseline for the next Migration, in this case, the generated model is in the pending or undetermined status. We need to migrate the Configuration class under the FlightMigrations directory generated above, so specify-ConfigurationTypeName after the Add-Migration command, and then specify the first base shelf Name through-Name.

Add-Migration -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration -Name Initial

Or

Add-Migration -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration "Initial"

Finally, you only need to use Update-database to persistently generate tables in the database.

Update-Database -ConfigurationTypeName EntityFrameworkTransactionScope.Data.FlightMigrations.Configuration

Similarly, we use the preceding three-step command to migrate mongodbcontext. At last, we can clearly see that each context is migrated in different directories, as shown below:

There is no problem with the above migration. If we migrate each context to a folder separately, have we ever thought about migrating multiple contexts to the same directory folder and separating them, when we only have one context, the created folder is Migrations by default. We will generate different context migration configurations under the Migrtions folder.

Migrate multiple contexts to the same folder directory

This is actually quite simple. We can directly specify A folder after-MigrationDirectoty to generate the context, for example, C: \ A \ DbContext and EntityFramework. Let's take A look at this.

Enable-Migrations -ContextTypeName FlightDbContext -MigrationsDirectory Migrations\FlightDbContext

Enable-Migrations -ContextTypeName HotelDbContext -MigrationsDirectory Migrations\HotelDbContext

The other two steps run in the same way as the migration, and we will see the desired results.

The above migration will generate the FlightDb and ReservationDb databases and correspond to the FlightBookings and Reservations tables. Now, the two methods of multi-context migration are over. Let's continue with this topic.

Distributed transactions

Sometimes we need to manage transactions across databases. For example, in this scenario, there are two databases db1 and db2, while tb1 in db1, tb2 in db2, and tb1 and tb2 are associated at the same time, in the flight and reservation model we created above, we need to insert flight data and Reservation data to different databases at the same time. At this time, transaction consistency is required, so to deal with such requirements, in. NET 2.0, in the System. the TransactionScope class is provided in the Transaction namespace. This class provides a simple way to allow a code block to participate in a transaction without having to interact with the transaction itself. We strongly recommend that you create a TransactionScope object in the using block.

When TransactionScope is instantiated, the transaction manager needs to determine which transaction to participate in. Once confirmed, the instance will be involved in the transaction all the time. When creating a TransactionScope object, we need to pass the transactionscospontion enumeration with the following values:

  • Required: The instance must have a transaction. If the transaction already exists, use the existing transaction. Otherwise, a new transaction will be created.
  • RequiresNew: always create a new transaction for the instance.
  • Suppress: When an instance is created, other existing transactions are blocked because all operations in the instance are completed without other existing transactions.

Next, we use the second method in the above enumeration to implement flight booking. The simple logic is as follows:

Public class MakeReservation {FlightDBContext flight; mongodbcontext hotel; public MakeReservation () {flight = new FlightDBContext (); hotel = new mongodbcontext ();} // transaction processing method public bool ReservTrip (TripReservation trip) {bool reserved = false; // bind the transaction processing range using (var scope = new TransactionScope (TransactionScopeOption. requiresNew) {try {// flight Information flight. flightBookings. add (trip. filght); flight. saveChanges (); // Reservation Information hotel. reservations. add (trip. hotel); hotel. saveChanges (); reserved = true; // complete the transaction and submit the scope. complete () ;}catch (Exception ex) {throw ex ;}return reserved ;}}

The above ReservTrip method accepts the TripReservation object. This method defines TransactionScope, binds the Create operation for Flight and Hotel in the context of the transaction, and writes the code to the try-catch Block. If the SaveChanges method of the two entities is successfully executed, the transaction is completed; otherwise, the transaction is rolled back. Next, call the controller.

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");  } }

We add the flight reservation View:

@ Model EntityFrameworkTransactionScope. data. entity. tripReservation @ {ViewBag. title = "Create" ;}< h2 class = "text-center"> travel 

The view shows the UI as follows:

To run the application and check the transaction, we need to use the Distributed Transaction Processing Coordinator (DTC) service. The service updates two or more transactions with protected resources, such as databases, message queues, and file systems. First, make sure that DTC is enabled. Check and enable it in the service.

To enable the dtcsettings, click the following actions to directly run mongodcomcnfg.exe] to open the component service in one step.

  • Open Control Panel
  • Find management tools
  • Find Component Service

Next, fill in the relevant information for flight booking.

The above shows that the reservation is successful. Let's see if the data in the two databases is correctly inserted.

In the DTC service, if each submission is not aborted, the number of submissions will increase by 1. When we configure the reservation model, we will not set the primary key as the ID column, so when we repeat the primary key, let's look at the data in the table. We submit three times without repeating the primary key reservation. When the fourth time the primary key is entered as the third primary key, the result is as follows:

If we verify the data in the leFlightBookings and Reservations tables, the newly added records are not displayed. This means that the TransactionScope has managed the Transaction by bundling the connection with the Flight and Hotel databases in a single range, and monitored the Committed and Aborted Transaction.

Summary

Just as when we use the EntityFramework as the conceptual data access layer. as seen in the. net mvc application, we always recommend that you use TransactionScope to manage transactions when performing multiple database operations to store relevant data.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.