Транзакции в трехзвенках

Dmitry Gurianov
Дата: 13.04.2010 17:33:40
Привет, уважаемый all!

Тема достаточно избита, но по поисковым словам мне не удалось найти нужный тред.
В моем приложении реализованы уровни UI, BL, DAL. Последний предоставляет в первую очередь доступ как напрямую к таблицам, так и к сущностям, которые м.б. реализованы в нескольких таблицах. Для работы со сложными сущностями требуется, ессно, проводить все операции в рамках одной транзакции.
Например, есть сущность "Контакт" (Contact(ID, Data, ...)) и есть сущность "Контакт персоны", реализованная в таблицах Contact и таблице-связке UserContact(ID, UserID, ...)).
При модификации этой сущности изменения должны вноситься в обе таблицы сразу, т.к. юзер мог изменить как данные самого контакта, так и привязку его к юзеру.
Теперь вопросы.
1. На каком уровне приложения должны исчезнуть таблицы и остаться только сущности? Мой DAL умеет делать примитивные операции на уровне таблиц (через БД-шный процедурный интерфейс):
Contact_Ins, Contact_Upd, Contact_Del;
UserContact_Ins, UserContact_Upd, UserContact_Del;
но при этом содержит расширенный механизм, позволяющий изменять не только таблицы, но и сущности:
UserContactExt_Ins, UserContactExt_Upd, UserContactExt_Del, внутри которых происходит вызов примитивных операций выше.
Это - нормальная практика? Или механизм для работы с сущностью стоит запихать в БД?

2. Транзакционность.
В своем варианте я предполагаю, что транзакции буду делать в слое DAL, то есть, для примера выше будет происходить так:

public static void Delete(...)
{
    SqlConnection conn = new SqlConnection("blablabla");
    SqlTransaction tran = conn.BeginTransaction();

    // delete UserContact
    UserContactDAL.Delete(conn, ...);

    // delete Contact
    ContactDAL.Delete(conn, ...);

    tran.Commit;

    conn.Close();
}

В примере нет обработки исключений, но смысл понятен.
Стоит ли поступать таким образом или операции над сущностями и их транзакционность запихать в БД?

Буду признателен за другие советы.
Спасибо.
Max Pro
Дата: 13.04.2010 18:39:04
Dmitry Gurianov

Теперь вопросы.
1. На каком уровне приложения должны исчезнуть таблицы и остаться только сущности?
2. Транзакционность.
В своем варианте я предполагаю, что транзакции буду делать в слое DAL, то есть, для примера выше будет происходить так:

public static void Delete(...)
{
    SqlConnection conn = new SqlConnection("blablabla");
    SqlTransaction tran = conn.BeginTransaction();

    // delete UserContact
    UserContactDAL.Delete(conn, ...);

    // delete Contact
    ContactDAL.Delete(conn, ...);

    tran.Commit;

    conn.Close();
}
Стоит ли поступать таким образом или операции над сущностями и их транзакционность запихать в БД?

Буду признателен за другие советы.
Спасибо.

Не совсем понятно что такое DAL, хотя догадаться несложно, видимо речь идёт о библиотеке классов, работающей с СУБД. Мне представляется, что ты начитался книг или были лекции с упоминанием DAL ― вот там и находится правильный ответ. Я могу лишь предложить ответ без претензии на правильность. Он заключается в том, что код sql, например транзакции, твой DAL должен уметь реализовывать как через хранимые процедуры, так и без оных. Если ты будешь использовать хранимые процедуры, то начальство или учителя будут в восторге, так как это общепринятый подход. Если же СУБД не поддерживает хранимых процедур, а также в тех случаях, когда предполагается работа с разными СУБД, стоит хранить код в DAL. Многие считают хорошим тоном использование для твоих целей (сущностей) триггера, хотя общепринято избегать триггеров. По поводу образца кода: вместо строки
tran.Commit;
лучше обойтись без неё, добавив коммит в текст sql. Ещё по поводу строки
conn.Close();
в принципе правильно, этот подход общепринят, но некоторые морщатся от такого кода. Хотя Микрософт рекомендует не держать подключение, закрывая его при первой возможности, некоторые программисты считают себя умнее и советуют на весь сайт постоянно держать одно-единственное подключение, ставя все запросы в БД в очередь. Они аргументируют, что таким образом убивают двух зайцев: экономят время и ресурсы системы на создание подключения и защищают СУБД от хакерских атак против падения сервера от одновременного открытия множества подключений (при этом рекомендации Микрософт считаются неверными).Картинка с другого сайта.
Dmitry Gurianov
Дата: 13.04.2010 19:00:08
Да, DAL - библиотека классов, которые только умеют делать CRUD-ы ко всем используемым таблицам. Ничего хитрого там не содержится.

Насчет транзакций... В принципе, мне пофиг, где их делать - объем работы одинаковый. Если делать в БЛ, до это даст расширяемость на другие БД, но если делать в БД, то это избавит веб-сервер от лишних запросов в базу, и к этому варианту я сейчас склоняюсь. То есть, думаю определить интерфейс доступа и к таблицам и к сущностям полностью в БД, там же и расставить транзакции, где нужно. А для БЛ найдется другая работа. Я понимаю, что это и есть размазывание логики по слоям, но насколько сильно это неправильный подход?
Триггеры не люблю.
А коннекшены буду закрывать явно... предубеждение, если хотите :)
Насчет единого подключения... про хакерские атаки был не в курсе, но если припрет - переделаю в единое, а пока открываю сколько надо.
Max Pro
Дата: 13.04.2010 21:43:09
Dmitry Gurianov
... CRUD-ы ...

Насчет транзакций... В принципе, мне пофиг, где их делать - объем работы одинаковый. Если делать в БЛ, до это даст расширяемость на другие БД, но если делать в БД, то это избавит веб-сервер от лишних запросов в базу, и к этому варианту я сейчас склоняюсь. То есть, думаю определить интерфейс доступа и к таблицам и к сущностям полностью в БД, там же и расставить транзакции, где нужно. А для БЛ найдется другая работа. Я понимаю, что это и есть размазывание логики по слоям, но насколько сильно это неправильный подход?
Триггеры не люблю.
А коннекшены буду закрывать явно... предубеждение, если хотите :)
Насчет единого подключения... про хакерские атаки был не в курсе, но если припрет - переделаю в единое, а пока открываю сколько надо.

Ты крут, сплошная латинская терминология Картинка с другого сайта.
CRUD Картинка с другого сайта.
Где, интересно так учат. Ладно. Твоя библиотека должна не только «круд» реализовывать, а вообще любые инструкции sql.
БЛ Картинка с другого сайта. ― на ум приходит нехорошее слово. Правильнее по-русски это называется библиотекой классов.
Триггеры не любишь ― молодец.
Картинка с другого сайта.
Но имей ввиду, в реали, когда на работу пойдёшь, в СУБД у тебя уже скорее всего будет помойка, в том числе с триггерами. К этому надо привыкнуть, так как никакие уговоры убрать триггера на «товарищей» не подействуют, наоборот разозлят, над тобой будут смеяться и скажут, что крутые пацаны работают только на триггерах.
От хакерских атак одно подключение не спасёт, это я просто так высмеиваю шибко «умных» людей.
В целом ты правильно мыслишь, одобряю.
Dmitry Gurianov
Дата: 13.04.2010 22:01:07
Max Pro,

> Ты крут, сплошная латинская терминология CRUD
насчет терминологии - ну есть она, и вполне удобна - пусть будет :)

> Где, интересно так учат.
Работаю с базами данных и БД-ориентированными приложениями лет 10. Просто только сейчас делаю свой проект, делаю с нуля, и хочется сделать его в соответствии с текущим мейнстримом. А там, где работал, даже нормальная трехзвенка встречалась только раз, хотя работал и с большими системами в крупных компаниях.

> Но имей ввиду, в реали, когда на работу пойдёшь, в СУБД у тебя уже скорее всего будет помойка
Это и так ясно :) Нет идеальных приложений, если идеалом не считать то, что оно работает.
Dmitry Gurianov
Дата: 13.04.2010 22:07:26
Max Pro,

и все-таки

> Твоя библиотека должна не только «круд» реализовывать, а вообще любые инструкции sql.

Вопрос был в том, где помещать ту логику, которая заправляет множественным удалением/модификацией строк для всех таблиц одной сущности? В хранимке или в классах?
ShSerge
Дата: 13.04.2010 22:18:11
Max Pro
Картинка с другого сайта.

Ты не умеешь их готовить.
Max Pro
Дата: 14.04.2010 10:57:43
Dmitry Gurianov

Вопрос был в том, где помещать ту логику, которая заправляет множественным удалением/модификацией строк для всех таблиц одной сущности? В хранимке или в классах?

Отвечаю ещё раз: множественные операции - это транзакция или свободный набор инструкций. Их можно сделать как в хранимой процедуре (уровень СУБД), так и в библиотеке классов (уровень программы). И так и сяк правильно. Я предпочитаю уровень программы по одной простой причине: проще будет в любой момент сменить СУБД. Но большинство программистов так далеко не заглядывают, и поэтому предпочитают уровень СУБД.
ShSerge

Ты не умеешь их готовить.

Умею, надо уметь, вообще врага полезно в лицо знать.
ShSerge
Дата: 14.04.2010 11:22:06
Max Pro
...проще будет в любой момент сменить СУБД. Но большинство программистов так далеко не заглядывают, и поэтому предпочитают уровень СУБД...

На самом деле, иногда случается другое. Вот есть база, с которой работают из-под делфей, например, и требуется к ней прикрутить вэб-интерфейс. Кроме шуток, такое встречается чаще, чем смена СУБД. Так что, имхо, раз на раз не приходится.
Max Pro
Дата: 14.04.2010 12:22:11
ShSerge,

здесь нет противоречий