Поделиться IDbConnection, чтобы сохранить транзакцию локальной

Репозиторий данных, который обрабатывает объект Data, наследуемый от универсального интерфейса, а уровень DAL реализован как универсальный класс, который получает универсальный интерфейс как внедрение зависимостей. Ниже приводится дизайн:

Data Entity - Автомобиль

public class Vehicle
{
    public int Id {get; set;}

    public string Brand {get; set;}
}

Общий интерфейс - IData

public interface IData<T>
{
   IEnumerable<T> Select(IDictionary<string,object> parameters);

   int Update(IDictionary<string,object> parameters);

   int Delete(IDictionary<string,object> parameters);

   int insert(IDictionary<string,object> parameters);
}

Автосервис

public class VehicleData : IData<Vehicle>
{
   IEnumerable<Vehicle> Select(IDictionary<string,object> parameters)
   {
      using(IDbConnection conn = (Fetch Connection))
      {
         // Select Operation
      } 
   }

   int Update(IDictionary<string,object> parameters)
    {
      using(IDbConnection conn = (Fetch Connection))
      {
         // Update Operation
      } 
   }

   int Delete(IDictionary<string,object> parameters)
    {
      using(IDbConnection conn = (Fetch Connection))
      {
         // Delete Operation
      } 
   }

   int insert(IDictionary<string,object> parameters)
    {
      using(IDbConnection conn = (Fetch Connection))
      {
         // Insert Operation
      } 
   }
}

Реализация класса DAL:

public class DAL<T>
{
  public static IEnumerable<T> Select(IData<T> dataRepository, IDictionary<string,object> parameters)
   {
       return dataRepository.Select(parameters);
   }

// Implementation for Insert, Update and Delete
}

Я выполняю VehicleData с помощью DAL из вызывающего класса следующим образом.

IData<Vehicle> vehicleData = new VehicleData();

IDictionary<string,object> parameters = // Filled from client

DAL<Vehicle>.Select(vehicleData,parameters);

Проблема, с которой я сталкиваюсь, заключается в том, что в каждом методе CRUD IDbConnection создается в Using блок, таким образом расположенный в конце, как в локальном контексте, но есть сценарий, в котором несколько операций DAL над различными объектами должны быть частью единого контекста транзакции; если я продолжу аналогичным образом, открытый контекст транзакции будет повышен до распределенный уровень, так как открываются несколько ресурсов соединения, даже когда я могу сделать их в одном и том же контексте соединения, поскольку они выполняются один за другим. Проблема остается:

  1. Как разделить соединение между несколькими звонками, как DAL<Vehicle>.Update, DAL<Driver>.Update and DAL<Truck>.Update, так что можно избежать продвижения транзакции с локального на распределенное

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

1 ответ

Используете ли вы контейнер IoC для внедрения зависимости? В IoC есть несколько стилей жизни (для потока, для веб-запроса и т. Д.). Например, с помощью Windsor Castle вы можете использовать стиль жизни Scoped. И ваш код будет выглядеть так:

Создать соединение (linq2db):

container.Register(
    Component.For<DataConnection>().UsingFactoryMethod(x => 
        CreateDataConnection()).LifestyleScoped(),
    Component.For<IData<Vehicle>>()
        .ImplementedBy<VehicleData>().LifestyleScoped()
);

private static DataConnection CreateDataConnection()
{
    return new DataConnection(new SqlServerDataProvider("", SqlServerVersion.v2008), 
        @"Data Source=(local);Initial Catalog=DB1;Persist Security Info=True;User ID=user;Password=pwd");
}

Выполните некоторые операции с БД:

using (container.BeginScope())
{
    var db = container.Resolve<DataConnection>();
    db.BeginTransaction();
    container.Resolve<IData<Vehicle>>().Update(...);
    container.Resolve<IData<Vehicle>>().Update(...);
    container.Resolve<IData<Vehicle>>().Update(...);
    db.CommitTransaction();
}
Другие вопросы по тегам