Структура SQL вставки Транзакции для C / Parent / Child объектов - PullRequest
0 голосов
/ 13 октября 2019

Я занимаюсь разработкой бизнес-объектов на C #. Каждый объект имеет возможность сохранять себя в связанной базе данных, например, такой (каждый объект):

public void Save()
{
    //Collect object attributes and convert to SQLParameters
    //Add SQL Parameters to SQL command and BeginTrans   
    //Execute, if No Errors, commit, otherwise rollback   
}

Я начал реализацию наследования / родительской дочерней части, и я не знаю, как структурировать родительский объектФункция Save () с внутренними дочерними объектами, потому что:

  • Каждый дочерний объект имеет свой собственный метод Save (), в котором есть свои собственные Connection, SQL-команда, BeginTrans, логика параметров и логика отката и т. Д.
  • Каждый вызов Object.Save () является определенной хранимой процедурой для этого типа объекта / базы данных.
  • НАИБОЛЕЕ ВАЖНО: Я хочу, чтобы ПОЛНОЕ СОХРАНЕНИЕ откатывалось, если какой-либо дочерний объект Сохранить сбой.

Например:

  • Если у объекта "Клиент" есть дочерние объекты "CustomerInfo", "Account" и "Dependents".

  • Когда выполняется Customer.Save, если сохранение для дочерних объектов «CustomerInfo» и «Account» выполнено успешно, но затем сохранение для дочернего объекта «Dependents FAIL», тогда я хочупредыдущие сохранения сохраняются для отката до вызывающего родительского объекта Customer.

Каков наилучший способ сделать это?

Я хотел бы сохранить логику для сохранения (форматирование, выполнение и откат параметров), инкапсулированных в каждом объекте, т.е.

Примерно так:

public void ParentSave()
{ 
   Begin Transaction

   Try
   {
   //For each CHILD Object
   //ChildObject.Save()
   }
   Catch(Save Fail)
   {
      //Rollback all executed saves/transaction(s)
    }

   IF(Success)
   {
      //Save parent
      Commit parent/overall transaction
    }
}

Я знаю, что могу использовать область действия «транзакция», но я не уверен, как ее структурироватьили если бы у меня были "вложенные" области транзакций. Я никогда раньше не использовал транзакцию Scope. Я знаю, что Transaction работает с вложенными транзакциями Begin / Commit (истинное принятие не происходит до тех пор, пока счетчик begin trans не достигнет 1), но работает ли оно для вложенных транзакций, используя их объект Connection / SQLCommand?

  • Относительно «объема транзакции»: если каждый объект имеет свое сохранение в своей собственной инкапсулированной функции (каждый объект save () запускает свое собственное соединение, команду SQL, выполняет Begin / commit, выполняет и закрывает объект команды SQL) **

  • Я НЕ хочу писать конкретную хранимую процедуру для каждой родительской / дочерней схемы (т. Е. Иметь сохраненный процесс для каждого варианта родительских / дочерних объектов).

  • Если бы это было НЕОБХОДИМО, я мог бы написать логику для каждого объекта, чтобы получить свою собственную информацию SQLParameters / command, чтобы вызывающий родительский объект мог объединить их и выполнить их в одной большой поэтапной транзакции, но я бы не стал.

  • Если мне нужно написать поэтапную транзакцию, должен ли я использовать «Sql SavePoints»? Почему, почему нет? Я предполагаю НЕТ, как будто есть какие-либо ошибки, я откатываю ВСЮ вещь назад.

  • Я мог бы передать объект соединения, если необходимо, чтобы "цепочка" цепочки сохранялась этим родительским объектом.

1 Ответ

1 голос
/ 15 октября 2019

Я бы перегрузил Save и сделал бы его функцией:

public bool Save()
{
    //Open SqlConnection

    //Begin Transaction

    bool success = Save(cn, Trans);

    if (success)
    {
        //Commit

        return true;
    }
    else
    {
        //Rollback

        return false;
    }
}

public bool Save(SqlConnection cn, SqlTransaction trans)
{
    //Save self using cn and trans. If fails, immediately return false.
    //Save each child using Save(cn, trans). If any one fails, immediately return false.
    //If no failures, return true.
}

Если вы хотите сохранить объект, вызовите Save() (без аргументов).

Save()создаст новое соединение и транзакцию, а затем вызовет Save(SqlConnection cn, SqlTransaction trans), которая попытается сохранить объект, используя только что созданное соединение и транзакцию. Save(SqlConnection cn, SqlTransaction trans) будет затем рекурсивно вызывать себя на всех дочерних объектах, пока все не будет сохранено сверху вниз.

Если что-то не получится в любой точке, Save(SqlConnection cn, SqlTransaction trans) вернет false полностью обратно в стек вызововк начальному Save(), который инициирует откат. Если сбоев нет, он вернет true, что приведет к фиксации.

...