Search code examples
c#transactionscopemsdtc

C# Transactionscope - insert/select in same transaction, multiple connections


I want to have a parent object delete itself and it's child object in a single transactionscope. I also want to check in both cases if the object to delete exists, and if the user has rights to the object. Consider the following code:

I get the MSDTC on server is unavailable exception. Is there anyway to pass the connection through my service methods?

Please see the example below:

// classes Flight, FlightService, FlightDao // classes Pilot, PilotService, PilotDao

// FlightService
public void deleteFlight(Flight flight) {
    FlightDao flightDao = new FlightDao();
    Flight existingFlight = flightDao.findById(flight.Id);
    if (existingFlight != null) {
        using (TransactionScope scope = new TransactionScope()) {
            try {
                PilotService.Instance.deletePilot(flight.Pilot);
                flightDao.delete(flight);
            } catch (Exception e) {
                log.Error(e.Message, e);
                throw new ServiceException(e.Message, e);
            }
            scope.Complete();   
        }
    }       
}

// PilotService
public void deleteFlight(Pilot pilot) {
    PilotDao pilotDao = new PilotDao();
    Pilot existingPilot = pilotDao.findById(pilot.Id); // THIS LINE RIGHT HERE THROWS EXCEPTION
    if (existingPilot != null) { 
        using (TransactionScope scope = new TransactionScope()) {
            try {               
                pilotDao.delete(pilot);
            } catch (Exception e) {
                log.Error(e.Message, e);
                throw new ServiceException(e.Message, e);
            }
            scope.Complete();   
        }
    }       
}

Solution

  • The problem here was that I was trying to use the same SqlDataReader multiple times within the same loop. This defintiely does not work inside a transaction.

    Example:

    SqlCommand command = new SqlCommand(...);
    SqlDataReader reader = command.ExecuteReader();
    if (reader.read()) {
      return buildMyObject(reader);
    }
    
    private MyObject buildMyObject(SqlDataReader reader) {
      MyObject o1 = new MyObject();
      // set fields on my object from reader
    
      // broken! i was attempting create a new sql connection here and attempt to use a reader
      // but the reader is already in use.
      return o1;
    }