C# Transactionscope - вставить / выбрать в одной транзакции, несколько соединений

Я хочу, чтобы родительский объект удалил сам себя и его дочерний объект в одной транзакции. Я также хочу проверить в обоих случаях, существует ли объект для удаления и есть ли у пользователя права на этот объект. Рассмотрим следующий код:

Я получаю MSDTC на сервере недоступное исключение. Есть ли способ передать соединение через мои методы обслуживания?

Пожалуйста, смотрите пример ниже:

// классы Flight, FlightService, FlightDao // классы 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();   
        }
    }       
}

2 ответа

Решение

Проблема была в том, что я пытался использовать один и тот же SqlDataReader несколько раз в одном цикле. Это определенно не работает внутри транзакции.

Пример:

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

Вы используете несколько слоев контекста данных с транзакциями. Вам нужно передать один другому. Вызов " deletePilot " должен выполняться в том же контексте данных. Одним из решений является наличие конструкторов на уровне доступа к данным для принятия контекста данных из другой службы данных. Они будут выполнять операции в том же контексте.

public void deleteFlight(IYourDataContext context, Pilot pilot) {
PilotDao pilotDao = new PilotDao(context);
//do operations now in same context.
...
Другие вопросы по тегам