Я 2 года занимаюсь разработкой корпоративных (бизнес) приложений. Как вы знаете, очень большую часть в такого типа приложениях занимает работа с БД. И очень важно правильно ее оформить, потому что при разрастании проекта за несколько тысяч строк (по моему опыту примерно 10000 строк) появляются некоторые проблемы. Можно выделить 2 основные проблемы:
1) Изменение схемы БД. На каком-то уровне оно становится сложным или просто невозможным. Например мы хотим перенести какое-то поле в отдельную таблицу, а в оригинальном поле указывать ID строки из этой новой таблицы. Вполне реальная ситуация что это может понадобится. Но теперь мне приходится перелопачивать сотни запросов в программе и десятки хранимых процедур, а потом молиться что нигде не вывалится скрытый косяк.
2) Смена СУБД. No comments.
Понимаю, что способов оформления работы с БД может быть много. Это может быть тупое написание SQL-кода в обработчике кнопки, это может быть оформление отдельного класса, в котором этот код уже будет записан, это может быть тот же Query Object, и т.д. Вопрос в том какой метод наиболее эффективен и распространен при разработке корпоративных приложений среднего размера (под средним размером я понимаю пару десятков тысяч строк кода написанного вручную и БД из пары десятков таблиц)?
Опишу, как я оформляю работу с БД.
Если какое-то обращение к БД — единичное, т.е. запрос очень специфический и его вызов происходит только в одном месте программы, то я не отделяю его от кода формы, т.е. пишу его прямо в обработчике события или отдельным методом класса формы/контрола, например так:
Пока писал пример, возник попутный вопрос:
Насколько нужно/ненужно использовать хранимые процедуры/функции? Лично мне это решение зачастую кажется более удобным по нескольким причинам: читабельность кода в программе (просто видим имя процедуры а не длинный SQL запрос и сразу все понимаем), простота изменения (если нужно внести изменения, зачастую изменяем только ХП на сервере а не изменяем что-то в нескольких местах в программе где она используется), ну и для меня не очень важный фактор — производительность.
Ладно, отвлекся, идем дальше.
Если запрос или его модификация должен вызываться из нескольких мест в программе, то я его оформляю в виде статического метода в классе типа CommonFuncs:
public static double GetPartPrice(int ManufacturerID, int SupplierID, string PartN, MySqlConnection conn)
{
try
{
MySqlCommand command = new MySqlCommand("GetPartPrice", conn);
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.Add("?ManufacturerID_", MySqlDbType.Int32).Value = ManufacturerID;
command.Parameters.Add("?SupplierID_", MySqlDbType.Int32).Value = SupplierID;
command.Parameters.Add("?PartN_", MySqlDbType.VarChar).Value = PartN;
command.Parameters.Add("?Result", MySqlDbType.Double).Direction = System.Data.ParameterDirection.ReturnValue;
command.ExecuteNonQuery();
return Convert.ToDouble(command.Parameters["?Result"].Value);
}
catch (Exception ex)
{
common.ShowException("An error occurred while trying to get part price from the database.\n\n" +
"Debug info:\ncommon.cs, GetPartPrice()\n", ex.Message);
return 0;
}
}
Если работа происходит с таблицей (всмысле гридом) обычно стараюсь работать через SelectCommand, UpdateCommand и т.д. класса SqlDataAdapter, типа так:
...
adapterNotScanned.SelectCommand = db.BarcodeSystem.CreateDataAdapterSelectCommand(conn);
adapterNotScanned.SelectCommand.Parameters.Add("?IsScanned", MySqlDbType.Bit).Value = false;
adapterNotScanned.SelectCommand.Parameters.Add("?IsPacked", MySqlDbType.Bit).Value = false;
adapterNotScanned.UpdateCommand = db.BarcodeSystem.NotScannedUpdateCommand(conn);
adapterNotScanned.TableMappings.Add("parts", "partsNotScanned");
...
// В классе db.BarcodeSystem все выглядит типа так:public static MySqlCommand CreateDataAdapterSelectCommand(MySqlConnection conn)
{
string strSQL;
strSQL = "SELECT blablabla FROM parts WHERE Customer = ?Customer AND OrderDebited = true AND " +
"OrderInvoiced = false AND IsScanned = ?IsScanned AND IsPacked = ?IsPacked ORDER BY ManufacturerID, PartN";
MySqlCommand cmd = new MySqlCommand(strSQL, conn);
return cmd;
}
Вот в общем-то и все. Так я делаю работу с БД.
Думаю, что мой вопрос и поднятая тема очень важны, и будут очень полезны большому количеству начинающих и средних программистов.
Так что... Направьте на путь истинный?
Заранее большое спасибо. С уважением.
Re: Оформление работы с БД в корпоративных приложениях - как
Здравствуйте, Kazna4ey, Вы писали:
K> Я 2 года занимаюсь разработкой корпоративных (бизнес) приложений. Как вы знаете, очень большую часть в такого типа приложениях занимает работа с БД.
Здравствуйте, Kazna4ey, Вы писали:
K>1) Изменение схемы БД. На каком-то уровне оно становится сложным или просто невозможным. Например мы хотим перенести какое-то поле в отдельную таблицу, а в оригинальном поле указывать ID строки из этой новой таблицы. Вполне реальная ситуация что это может понадобится. Но теперь мне приходится перелопачивать сотни запросов в программе и десятки хранимых процедур, а потом молиться что нигде не вывалится скрытый косяк. K>2) Смена СУБД. No comments.
Это решается введением специального Data Access Layer, находящегося "под" Business Logic Layer и предоставляющего последнему интерфейс в терминах Business Objects (иногда Data Transfer Objects, если логика Business Objects вынесена во внешние манипуляторы).
В этом случае изменение схемы БД, самой БД и т.д. во-первых, локализованно в пределах DAL, а во-вторых, как следствие во-первых, тестирование DAL необходимо и достаточно для тесрирования целостности схемы БД.
Тестирование БД задача, вообще говоря, премерзкая, но если приложение действительно корпоративное, весьма неоходимая. Сложность тестирования DAL заключается не только в выделении test cases, но и подготовке исходных данных. Нередко, для того чтобы протестировать некоторый запрос, необходимо заполнить кучу таблиц.
Пожалуйста, свои ответы старайтесь делать подробнее, то что для вас совершенно просто — для других может быть совершенно непонятно, и, пожалуйста, примеры, больше примеров кода, как это сделал например я.
Заранее спасибо!
Re: Оформление работы с БД в корпоративных приложениях - как
Здравствуйте, Kazna4ey, Вы писали:
K>Доброе время суток,
K> Я 2 года занимаюсь разработкой корпоративных (бизнес) приложений. Как вы знаете, очень большую часть в такого типа приложениях занимает работа с БД. И очень важно правильно ее оформить, потому что при разрастании проекта за несколько тысяч строк (по моему опыту примерно 10000 строк) появляются некоторые проблемы. Можно выделить 2 основные проблемы:
Две вещи звучат странно. Во-первых, меня удивляло зачем считать количесттво строк кода. Во — вторых, пишете "бизнес приложения" два года и задаёте такие странные вопросы.
Писать sql запросы в обработчиках событий на форме — это мягко говоря не очень правильно. Можно явно выделить логику работы с СУБД в отдельный набор классов, т.е. слой. Например
public class DataAccessLayer {
public IList<Order> GetOrdersForDate(DateTime date) {
}
public IList<Order> GetOrdersByCustomer(Customer customer) {
}
}
Фактически у вас такая структура где-то была. А вообще для корпоративных приложений сейчас можно использовать ORM, например Hibernate или iBattis, в зависимости от конкретники задачи. Последний хорошо использоват ьв случае большого количества legacy кода на sql. В случае применения ORM data access objects можно не применять и рассматривать ORM как абстракцию от специфики СУБД. Данный вопрос неодназнеачен и далеко не все согласны отказываться от DAO, только недавно большая дискуссия по сабжу была.
Что ксасается использования хранимок, то тут сколько противников столько же и сторонников. Минусом хранимок явлются как минимум: сложность поддержки, меньшая масштабируемость, зависимость от конкретной СУБД. Для меня этого достаточно , что бы от них отказаться.
Re[2]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Aviator, Вы писали:
A>>Минусом хранимок явлются как минимум: сложность поддержки, меньшая масштабируемость, зависимость от конкретной СУБД. A>Это минус по сравнению с чем? По сравнению с вписанными в код SQL запросами?!
По сравнению с вариантом без привлечения хранимых процедур.
Re[4]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, Aviator, Вы писали:
A>>>Минусом хранимок явлются как минимум: сложность поддержки, меньшая масштабируемость, зависимость от конкретной СУБД. A>>Это минус по сравнению с чем? По сравнению с вписанными в код SQL запросами?! A>По сравнению с вариантом без привлечения хранимых процедур.
ИМХО ХП напротив проще поддерживать потому что:
ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов.
ХП позволяют держать в БД не только данные, но и код управления данными, обеспечивая их целостность (группировку запросов в транзакции и т.п.) на уровне хранения. Естественно, гораздо лучше когда это делает разработчик БД, а не прикладной программист знающий только имена таблиц и столбцов. Кроме того, использование ХП позволяем автоматически тестировать самый низкоуровневый код работы с данными. Это особенно актуально при изменении схемы (добавлении столбца, а то и таблицы). Так же, тестируя ХП на объёмах данных разных порядков можно делать косвенные выводы об асимптоте скорости работы без ручного разбора планов исполнения SQL запросов и прогнозировать наличие узких мест до того как кто-то в них застрял.
Прикладной программист знающий только имена таблиц и столбцов не миф. Во-первых, имея уже готовую (постоянно меняющуюся!) БД узнать всё остальное может быть проблемно, во-вторых просто лень.
Про масштабируемость не понял к чему было. Как использование ХП уменьшает масштабируемость системы? Очень интересно послушать, желательно с примерами.
Зависимость от конкретной СУБД будет всегда. Дело даже не в синтаксических различиях диалектов SQL, а в разном объёме предоставляемой функциональности. Система не может быть независимой от СУБД на уровне DAL. Это ИМХО миф и утопия.
Здравствуйте, adontz, Вы писали:
A> ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов.
А откуда программист узнает названия ХП, порядок их вызова и какие параметры им передавать?
A> ХП позволяют держать в БД не только данные, но и код управления данными, обеспечивая их целостность (группировку запросов в транзакции и т.п.) на уровне хранения. Естественно, гораздо лучше когда это делает разработчик БД, а не прикладной программист знающий только имена таблиц и столбцов.
Целостность лучше всего обеспечивать на уровне приложения с помощью интуитивно-понятных для пользователя способов. К примеру, на форме необходимые поля должны быть подсвечены и кнопка "OK" должна блокироваться, если они не заполнены. Это намного понятнее, чем сообщение "Error 2422934: Foreign key constraint violation".
БД тут должна работать в качестве "последнего рубежа" обороны — если невалидные данные все-таки прорвались, то хотя бы целостность данных в базе у нас сохранится. Для такой валидации прекрасно подходят триггеры и разные системы валидации в БД.
A> Кроме того, использование ХП позволяем автоматически тестировать самый низкоуровневый код работы с данными. Это особенно актуально при изменении схемы (добавлении столбца, а то и таблицы). Так же, тестируя ХП на объёмах данных разных порядков можно делать косвенные выводы об асимптоте скорости работы без ручного разбора планов исполнения SQL запросов и прогнозировать наличие узких мест до того как кто-то в них застрял.
Со слоем DAL все точно так же.
A> Прикладной программист знающий только имена таблиц и столбцов не миф. Во-первых, имея уже готовую (постоянно меняющуюся!) БД узнать всё остальное может быть проблемно, во-вторых просто лень.
Вот поэтому и нужен слой DAL, который изолирует "прикладного программиста" от знания деталей базы данных и дает намного более понятный и приятный объектный интерфейс. Ну и создание DAL можно существенно автоматизировать с помощью ORM.
Sapienti sat!
Re[6]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, Cyberax, Вы писали:
A>> ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов. C>А откуда программист узнает названия ХП, порядок их вызова и какие параметры им передавать?
Если нет документации (кстати почему её нет?), то оттуда же, откуда и имена таблиц — из какого-нибуь Object Browser. Впрочем, если исключить экстрим, и вернутся к документации, то для меня достаточно очевидно, какой из приведённых ниже двух примеров лучше.
Информация о пользователях хранится к таблице Users. Таблица Users содержит столбцы ID, Login, Password, FirstName, LastName. Индексированными являются столбцы ID, Login и Password.
Для доступа к данным о пользователях следует спользовать следующие ХП:
Программист пользующийся ХП из второго состояния не в состоянии напортачить. Программист пользующийся первым вариантом вполне может отмочить что-то вроде
UPDATE Users SET Password=NewPassword WHERE FirstName='John' AND LastName='Smith'
A>> ХП позволяют держать в БД не только данные, но и код управления данными, обеспечивая их целостность (группировку запросов в транзакции и т.п.) на уровне хранения. Естественно, гораздо лучше когда это делает разработчик БД, а не прикладной программист знающий только имена таблиц и столбцов. C>Целостность лучше всего обеспечивать на уровне приложения с помощью интуитивно-понятных для пользователя способов. К примеру, на форме необходимые поля должны быть подсвечены и кнопка "OK" должна блокироваться, если они не заполнены. Это намного понятнее, чем сообщение "Error 2422934: Foreign key constraint violation". C>БД тут должна работать в качестве "последнего рубежа" обороны — если невалидные данные все-таки прорвались, то хотя бы целостность данных в базе у нас сохранится. Для такой валидации прекрасно подходят триггеры и разные системы валидации в БД.
Я был бы благодарен, если бы ты не только писал, но и читал. Твой ответ абсолютно не в тему. Перечитай моё сообщение ещё раз, особенно отрывок
обеспечивая их целостность (группировку запросов в транзакции и т.п.)
Ты считаешь, что группировку в транзакции надо делать на уровне обработчика событий кнопки ОК?!
A>> Кроме того, использование ХП позволяем автоматически тестировать самый низкоуровневый код работы с данными. Это особенно актуально при изменении схемы (добавлении столбца, а то и таблицы). Так же, тестируя ХП на объёмах данных разных порядков можно делать косвенные выводы об асимптоте скорости работы без ручного разбора планов исполнения SQL запросов и прогнозировать наличие узких мест до того как кто-то в них застрял.
C>Со слоем DAL все точно так же.
Наличие слоя DAL абсолютно перпендикулярно. Тут обсуждаются примущества наличия ХП перед их отсутвием и напротив. DAL может существовать и отсутствовать и в том и в другом случае.
A>> Прикладной программист знающий только имена таблиц и столбцов не миф. Во-первых, имея уже готовую (постоянно меняющуюся!) БД узнать всё остальное может быть проблемно, во-вторых просто лень. C>Вот поэтому и нужен слой DAL, который изолирует "прикладного программиста" от знания деталей базы данных и дает намного более понятный и приятный объектный интерфейс. Ну и создание DAL можно существенно автоматизировать с помощью ORM.
Здравствуйте, adontz, Вы писали:
A>>>>Минусом хранимок явлются как минимум: сложность поддержки, меньшая масштабируемость, зависимость от конкретной СУБД. A>>>Это минус по сравнению с чем? По сравнению с вписанными в код SQL запросами?! A>>По сравнению с вариантом без привлечения хранимых процедур.
A>ИМХО ХП напротив проще поддерживать потому что:
Вы когда-нибудь пытались поддерживать ХП? Я имею в виду более менее большие проекты, а не базы с парой десяткой табличек и 30-40 процедурами.
A> ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов.
В наше время все давно используют различные OR/M.
A> ХП позволяют держать в БД не только данные, но и код управления данными, обеспечивая их целостность (группировку запросов в транзакции и т.п.) на уровне хранения.
Что чрезвычайно усложняет сопровождение такого проекта, т.к. ХП гораздо сложнее отлаживать и тестировать. О читабельности я вообще молчу.
A>Естественно, гораздо лучше когда это делает разработчик БД, а не прикладной программист знающий только имена таблиц и столбцов.
Потому и используют OR/M. Нету никаких таблиц. Нету никаких столбцов. Есть объекты DAL-уровня со свойствами. Есть соотвествующие объекты BLL уровня с бизнес логикой. Все связи минимальны благодаря IoC-контейнерам (Spring, Castle Windsor и т.п.). Код тщательно документируется. В наличии богатый IntelliSense инструментарий, фреймворки для тестирования типа nUnit с RhinoMocks, средства для автоматического создания документации, мощный отладчик, прекрасная читабельность кода, отсутствие привязки к конкретной БД и минимальная зависимость от схемы БД, высокая масштабируемость.
A>Кроме того, использование ХП позволяем автоматически тестировать самый низкоуровневый код работы с данными.
Наоборот не позволяет автоматически тестировать. Нет, конечно можно писать тесты для тестирования хранимых процедур, но они редко могут быть полными.
A>Зависимость от конкретной СУБД будет всегда. Дело даже не в синтаксических различиях диалектов SQL, а в разном объёме предоставляемой функциональности. Система не может быть независимой от СУБД на уровне DAL. Это ИМХО миф и утопия.
Да? Какой кошмар...
... << RSDN@Home 1.2.0 alpha rev. 746>>
Re[7]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, adontz, Вы писали:
A>>> ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов. C>>А откуда программист узнает названия ХП, порядок их вызова и какие параметры им передавать? A>Если нет документации (кстати почему её нет?)
А если есть документация по схеме, то откуда тогда программисты знающие только про колонки в базе?
>то оттуда же, откуда и имена таблиц — из какого-нибуь Object Browser. Впрочем, если исключить экстрим, и вернутся к документации, то для меня достаточно очевидно, какой из приведённых ниже двух примеров лучше.
[skip] A>Программист пользующийся ХП из второго состояния не в состоянии напортачить.
Жуть. У нас куча простых однострочных процедур ТОЛЬКО для одной простенькой сущности, даже без связей. Да еще и нет поддержки оптимистических блокировок.
A>Программист пользующийся первым вариантом вполне может отмочить что-то вроде A>UPDATE Users SET Password=NewPassword WHERE FirstName='John' AND LastName='Smith'
У меня было бы описано так:
public class User
{
private long id,version; //Вообще-то обычно они выделены в базовый класс
@Column(length=64)
private String firstName, lastName, login, password;
//Добавим еще для интереса аудит.
@Requisite(Role.SERVER)
private List<UserAuditRecord> auditRecords;
//getter'ы и setter'ы пропускаем по причине их тривиальности.
}
Усё.
Прикладной программист работает с объектами, простые изменения он может персистить вот так:
Session sess=...;
User user=sess.get(User.class, userId);
user.setFirstName("Vasja");
sess.saveOrUpdate(user);
А вот если он попробует так поменять auditRecords — получит в лоб исключением, так как для этого код должен явным образом взять роль "SERVER". Для реального User'а @Requisite будет стоять не на один метод, а на весь класс.
Система еще обеспечит нам автоматическое оптимистическое версирование по полю version.
C>>БД тут должна работать в качестве "последнего рубежа" обороны — если невалидные данные все-таки прорвались, то хотя бы целостность данных в базе у нас сохранится. Для такой валидации прекрасно подходят триггеры и разные системы валидации в БД. A>Я был бы благодарен, если бы ты не только писал, но и читал. Твой ответ абсолютно не в тему. Перечитай моё сообщение ещё раз, особенно отрывок A>
A>обеспечивая их целостность (группировку запросов в транзакции и т.п.)
A>Ты считаешь, что группировку в транзакции надо делать на уровне обработчика событий кнопки ОК?!
Да, при открытии формы — начинаем бизнес-транзакцию с оптимистическим версированием, при коммите ее заканчиваем. Механизм работы с транзакциями в БД — отдаем на откуп middleware.
Скажем, у меня это выглядит так:
@Transactional(rollbackFor=Throwable.class)
public class QCManagerBean implements QCManagerRemote
{
...
//Приостанавливает текущую транзакциию на время исполнения метода и начинает новую
@Transactional(propagation=REQUIRES_NEW)
public void businessMethod1(...)
{
}
//Обязан выполняться внутри транзакции, но сам ее не начинает
@Transactional(propagation=MANDATORY)
public void businessMethod2(...)
{
}
//Автоматически начинает транзакцию, если ее нет.public void businessMethod3(...)
{
}
}
И я вообще слабо понимаю что ты понимаешь под "группировкой в транзакции". Явный begin/commit из ХП? Так это вообще в морг.
C>>Со слоем DAL все точно так же. A>Наличие слоя DAL абсолютно перпендикулярно. Тут обсуждаются примущества наличия ХП перед их отсутвием и напротив. DAL может существовать и отсутствовать и в том и в другом случае.
Не перпендикулярно. Имея выделенный слой DAL и XP мы просто будем делать лишнюю работу. Скажем твой пример с пользователем можно точно так же сделать с помощью DAL'а в виде класса UserDAO, с которым и будет работать прикладной программист.
Естественно, за работу с данными минуя DAL — бить ногами.
C>>Вот поэтому и нужен слой DAL, который изолирует "прикладного программиста" от знания деталей базы данных и дает намного более понятный и приятный объектный интерфейс. Ну и создание DAL можно существенно автоматизировать с помощью ORM. A>А кто напишет это DAL? Сам возьмётся?
Тот программист, который занимается интеграцией с БД. Только не надо сказок, что его нет.
Я прекрасно видел реальные проекты, в которых типА-чистА-крутой-DBA делает все в хранимых процедурах. Обычно кончалось тем, что разработка замедлялась до улиточной скорости из-за того, что DBA приходилось одновременно делать работу от 10 человек (типа: "А мне нужна смена пароля по секретному вопросу!!", "А пароль — case sensetive?" и "Когда же добавят поле 'домен'??").
Sapienti sat!
Re[6]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, kuj, Вы писали:
A>>ИМХО ХП напротив проще поддерживать потому что: kuj>Вы когда-нибудь пытались поддерживать ХП? Я имею в виду более менее большие проекты, а не базы с парой десяткой табличек и 30-40 процедурами.
Поддержкой ХП занимаются программисты БД. Я не такой. Они на моей памяти не жаловались. Мне с ХП работать на порядки проще, чем изучать потроха конкретной схемы.
A>> ХП пишет тот же, кто разработал схему БД, а значит ХП лучше учитывают наличие или отсутствие индексов. прикладной же программист вставляющий в свой код SQL запросы в лучшем случае прочитал названия таблиц и столбцов. kuj>В наше время все давно используют различные OR/M.
ORM всего лишь обёртки для мапинга и сопутствующих операций. Если транзакция нужна, а её нет ORM не спасёт. Если делается выборка по неиндексированному столбцу ORM опять таки не спасёт. Спасают, в плане не дают облажатся, именно ХП.
kuj>Что чрезвычайно усложняет сопровождение такого проекта, т.к. ХП гораздо сложнее отлаживать и тестировать. О читабельности я вообще молчу.
Извини, ты с ХП работал вообще?
kuj>Потому и используют OR/M. Нету никаких таблиц. Нету никаких столбцов. Есть объекты DAL-уровня со свойствами. Есть соотвествующие объекты BLL уровня с бизнес логикой. Все связи минимальны благодаря IoC-контейнерам (Spring, Castle Windsor и т.п.). Код тщательно документируется. В наличии богатый IntelliSense инструментарий, фреймворки для тестирования типа nUnit с RhinoMocks, средства для автоматического создания документации, мощный отладчик, прекрасная читабельность кода, отсутствие привязки к конкретной БД и минимальная зависимость от схемы БД, высокая масштабируемость.
Повторюсь. ORM всего лишь обёртки для мапинга и сопутствующих операций. Если транзакция нужна, а её нет ORM не спасёт. Если делается выборка по неиндексированному столбцу ORM опять таки не спасёт. Спасают, в плане не дают облажатся, именно ХП.
Именно тот факт, что ORM являясь очень удобными средствами никак не контроллирующим разработчика и приводит к отказу от ORM в действительно крупных проектах. Когда знакомишься с Hiberbnate первая мысль это ВАУ, потом начинают закрадываться сомнения, а чуть позже задаёшь на форуме вопрос "А без HQL можно?" потому что учёт специфики схемы БД не локализован, а разбросан по проекту. Когда БД растёт вместе с проектом и эта специфика меняется начинаются странные падения производительности "хотя совсем недавно всё работало". Получаем мину замедленного действия. Единственное известно мне исключение — это BLT, но там просто функциональности недостаточно чтоб мины делать (хотя в том что BLT делает, она на высоте).
A>>Кроме того, использование ХП позволяем автоматически тестировать самый низкоуровневый код работы с данными. kuj>Наоборот не позволяет автоматически тестировать. Нет, конечно можно писать тесты для тестирования хранимых процедур, но они редко могут быть полными.
Смотря что делают хранимые процедуры. Конечно, если у тебя реализация вида 1запрос-1ХП, то пользы и от ХП мало и от их тестирования.
A>>Зависимость от конкретной СУБД будет всегда. Дело даже не в синтаксических различиях диалектов SQL, а в разном объёме предоставляемой функциональности. Система не может быть независимой от СУБД на уровне DAL. Это ИМХО миф и утопия. kuj>Да? Какой кошмар...
Если тебе не совсем плевать на производительность, то да. Ты писал приложение, которое должно работать на MSSQL И MySQL? Это очень разные СУБД с разными заскоками. То что бегало на одной, на другой показывало просто УЖАСНУЮ производительность. Например в MySQL нет типа GUID, и если пойти на поводу у лени и хранить GUID'ы в строках, то получим падение производительности в разы. Разбиение на 4 int работало на ура, но никакая ORM не смогла это отобразить, что впрочем и не удивительно.
На самом деле нет никаких великих ORM и OODBMS. Есть реляционные БД со строгой математической теорией от которых никуда не деться именно в связи с огромной строгой математической теорией. Есть традиция ОО программирования от которйо тоже никуда не деться. а ещё есть маркетологи регулярно сулящие чему-нибудь смерть (RDBMS are dead, апплодисместы, хвала новым героям, бабки с Google AdSence ибо скандальное привлекает) и пытающиеся продать очередную серебрянную пулю. Нет ещё такого средства, которое бы эффективно отобразило хранящуюся в памяти объектную модель на данные в РСУБД без пинков и тычков. Когда надоедает пинать и тыкать, наступает просветление и просто делаешь всё руками. Ну или существенную часть.
Здравствуйте, Cyberax, Вы писали:
C>А если есть документация по схеме, то откуда тогда программисты знающие только про колонки в базе?
Потому что если есть возможность совершить ошибку, ты хоть миллион предупреждений повесь, всё равно найдётся дурак, который её совершит.
C>Жуть. У нас куча простых однострочных процедур ТОЛЬКО для одной простенькой сущности, даже без связей. Да еще и нет поддержки оптимистических блокировок.
Эти операции тебе понадобятся в любом случае. Никаких лишних сущностей тут нет.
C>
C>public class User
C>{
C> private long id,version; //Вообще-то обычно они выделены в базовый класс
C> @Column(length=64)
C> private String firstName, lastName, login, password;
C> //Добавим еще для интереса аудит.
C> @Requisite(Role.SERVER)
C> private List<UserAuditRecord> auditRecords;
C> //getter'ы и setter'ы пропускаем по причине их тривиальности.
C>}
C>
C>Усё.
Круто, кто это напишет? Даю намёк, разработчик БД знает только SQL (во всяком случае ему не платят за написание DAL или каких-либо обёрток). Это ситуация в которой я работал не один раз, мне дают голую БД (справедливости ради надо заметить очень хорошо продуманную), над которой надо что-то строить сверху.
C>Да, при открытии формы — начинаем бизнес-транзакцию с оптимистическим версированием, при коммите ее заканчиваем. Механизм работы с транзакциями в БД — отдаем на откуп middleware.
Это совсем другая транзакция, не надо путать тёплое с мягким. Если например, надо статью из категории "Разное" перенести в категорию "Юмор", то разумно на уровне БД в виде ХП реализовать MoveArticle объединяющую DELETE И INSERT в транзакцию, чтобы статья не подвисла без категории (и не оказалась сразу в двух). А вот уже в бизнес-транзакции можешь объединить массовый перенос статей в нечто болеее высокоуровневое, но INSERT И DELETE должны быть объеденены на уровне БД.
C>И я вообще слабо понимаю что ты понимаешь под "группировкой в транзакции".
Да.
C>Явный begin/commit из ХП? Так это вообще в морг.
Здрасьте.
C>Не перпендикулярно. Имея выделенный слой DAL и XP мы просто будем делать лишнюю работу. Скажем твой пример с пользователем можно точно так же сделать с помощью DAL'а в виде класса UserDAO, с которым и будет работать прикладной программист. C>Естественно, за работу с данными минуя DAL — бить ногами.
DAL и SQL пишут разные люди. Это не два раза одна и та же работа (хотя согласен, что ХП во многом посторяют DAL), это контракт вызова между разными модулями, написанными разными людьми.
A>>А кто напишет это DAL? Сам возьмётся? C>Тот программист, который занимается интеграцией с БД. Только не надо сказок, что его нет.
Он есть, но это не тот, который разрабатывает БД. И интеграция с БД далеко не основная его работа. Будешь удивлён, но программистов используют согласно языкам, а не задачам. Задача простая — хранить данные, но разделена на две части: DAL на C++/C#/Java/etc. и DB на SQL. Делают их два разных человека, причём тот кто пишет DAL пишёт не только его и читать с утра до вечера хинты SQL'щика (которые то ещё должен написать) на тему "туда не ходи, сюда ходи" как правило достаточно утомительно. Гораздо эффективнее выдать интерфейс БД в виде ХП, которые сами всё расскажут о том как и что можно делать и не дадут сделать "не так".
C>Я прекрасно видел реальные проекты, в которых типА-чистА-крутой-DBA делает все в хранимых процедурах. Обычно кончалось тем, что разработка замедлялась до улиточной скорости из-за того, что DBA приходилось одновременно делать работу от 10 человек (типа: "А мне нужна смена пароля по секретному вопросу!!", "А пароль — case sensetive?" и "Когда же добавят поле 'домен'??").
Извини, это проблема написания ТЗ и управления разработкой, а не ХП Будет ли пароль case sensitive и будет ли смена пароля по секретному вопросу решается usability специалистами, а не разработчиком БД и уазывается в ТЗ. Остальные читают.
Представь себе DAL для той же задачи хранящий всё в текстовых файлах (никаких ХП). Абсолютно та же ситуация наблюдалась бы. Это отсутствие чёткого ТЗ и только.
Здравствуйте, adontz, Вы писали:
C>>А если есть документация по схеме, то откуда тогда программисты знающие только про колонки в базе? A>Потому что если есть возможность совершить ошибку, ты хоть миллион предупреждений повесь, всё равно найдётся дурак, который её совершит.
В том числе и DBA в ХП, а эту ошибку потом будут долго отлаживать тупые прикладные пользователи, которые ни разу в жизни не написали ни одного запроса.
C>>Жуть. У нас куча простых однострочных процедур ТОЛЬКО для одной простенькой сущности, даже без связей. Да еще и нет поддержки оптимистических блокировок. A>Эти операции тебе понадобятся в любом случае. Никаких лишних сущностей тут нет.
Есть. Я могу выкинуть кучу ручного труда с помощью разных автоматических байндеров и валидаторов.
[skip] C>>Усё. A>Круто, кто это напишет? Даю намёк, разработчик БД знает только SQL (во всяком случае ему не платят за написание DAL или каких-либо обёрток). Это ситуация в которой я работал не один раз, мне дают голую БД (справедливости ради надо заметить очень хорошо продуманную), над которой надо что-то строить сверху.
Если DBA знает только SQL — то он не сможет понять ТЗ, написаное аналитиком. Так что возможны два варианта:
1. Аналитик дает задание девелоперам, те рисуют черновую схему базы данных (я это делаю прямо в коде, из которого автоматически строится схема). Эта схема с комментариями отдается DBA, который ее оптимизирует (расставляет нужные индексы, ставит дополнительные проверки, может денормализует что-нибудь). Оптимизированая схема отдается обратно девелоперам, которые подправляют под нее код (обычно требуется править совсем немного).
2. Аналитик дает задание DBA. DBA рисует схему и отдает ее программистам. Программисты по схеме строят DAL.
Случай когда тебе дают готовую схему БД означает, что приложение уже скорее всего было написано и работает. Тогда ничего не мешает тебе дать и готовый слой DAL (в виде отдельного модуля). Просто очень часто как раз делают псевдо-DAL на хранимках.
C>>Да, при открытии формы — начинаем бизнес-транзакцию с оптимистическим версированием, при коммите ее заканчиваем. Механизм работы с транзакциями в БД — отдаем на откуп middleware. A>Это совсем другая транзакция, не надо путать тёплое с мягким. Если например, надо статью из категории "Разное" перенести в категорию "Юмор", то разумно на уровне БД в виде ХП реализовать MoveArticle объединяющую DELETE И INSERT в транзакцию, чтобы статья не подвисла без категории (и не оказалась сразу в двух). А вот уже в бизнес-транзакции можешь объединить массовый перенос статей в нечто болеее высокоуровневое, но INSERT И DELETE должны быть объеденены на уровне БД.
Хороший пример. А если у нас нет операции MoveArticle? Как ты в случае БД
C>>И я вообще слабо понимаю что ты понимаешь под "группировкой в транзакции". A>Да. C>>Явный begin/commit из ХП? Так это вообще в морг. A>Здрасьте.
Досвиданья.
C>>Естественно, за работу с данными минуя DAL — бить ногами. A>DAL и SQL пишут разные люди. Это не два раза одна и та же работа (хотя согласен, что ХП во многом посторяют DAL), это контракт вызова между разными модулями, написанными разными людьми.
Процедуры DAL в виде selectByLogin/updatePassword замечательно пишут обычные программисты, точнее это все замечательно автоматизируется. Если их переложить на DBA — то он просто завязнет в куче мелких запросов (видел такое собственными глазами далеко не раз), да еще и проблемы с версированием БД начнутся.
На откуп DBA остаются только оптимизации сложных запросов и всякие сложные операции, требующие временных таблиц, километровых запросов и кувырков с переворотами. Вот тут, кстати, ХП как раз вполне подходят.
A>>>А кто напишет это DAL? Сам возьмётся? C>>Тот программист, который занимается интеграцией с БД. Только не надо сказок, что его нет. A>Он есть, но это не тот, который разрабатывает БД. И интеграция с БД далеко не основная его работа. Будешь удивлён, но программистов используют согласно языкам, а не задачам. Задача простая — хранить данные, но разделена на две части: DAL на C++/C#/Java/etc. и DB на SQL.
Вот чувствую, что оба делают лишнюю работу.
A>Делают их два разных человека, причём тот кто пишет DAL пишёт не только его и читать с утра до вечера хинты SQL'щика (которые то ещё должен написать) на тему "туда не ходи, сюда ходи" как правило достаточно утомительно. Гораздо эффективнее выдать интерфейс БД в виде ХП, которые сами всё расскажут о том как и что можно делать и не дадут сделать "не так".
Вот ты мне привел пример с XP для операций с User'ом. Не вижу там ни одного нетривиального SQL-оператора, который не смогу написать бы даже студент. Зачем тогда заставлять высококвалифицированного DBA заниматься этой ерундой?
C>>Я прекрасно видел реальные проекты, в которых типА-чистА-крутой-DBA делает все в хранимых процедурах. Обычно кончалось тем, что разработка замедлялась до улиточной скорости из-за того, что DBA приходилось одновременно делать работу от 10 человек (типа: "А мне нужна смена пароля по секретному вопросу!!", "А пароль — case sensetive?" и "Когда же добавят поле 'домен'??"). A>Извини, это проблема написания ТЗ и управления разработкой, а не ХП Будет ли пароль case sensitive и будет ли смена пароля по секретному вопросу решается usability специалистами, а не разработчиком БД и уазывается в ТЗ. Остальные читают.
Так решается. Вот в середине проекта юзабилист и решил — надо добавить возможность восстановления по секретному вопросу.
A>Представь себе DAL для той же задачи хранящий всё в текстовых файлах (никаких ХП). Абсолютно та же ситуация наблюдалась бы. Это отсутствие чёткого ТЗ и только.
Дело в том, что в таком случае программисты сами смогли бы добавить нужные вещи в DAL и в свои DB. А к DBA потом просто отправить изменения в схеме на review и оптимизацию.
А если мы даем программистам писать/править свои ХП — то тогда они уже у нас скорее всего не полные идиоты, неспособные понять даже простого SQL UPDATE.
Sapienti sat!
Re[10]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, Cyberax, Вы писали:
C>>>А если есть документация по схеме, то откуда тогда программисты знающие только про колонки в базе? A>>Потому что если есть возможность совершить ошибку, ты хоть миллион предупреждений повесь, всё равно найдётся дурак, который её совершит. C>В том числе и DBA в ХП, а эту ошибку потом будут долго отлаживать тупые прикладные пользователи, которые ни разу в жизни не написали ни одного запроса.
Извини, мы не об опечатках. Я ни разу не видел, чтобы разработчик БД сам написал SELECT с кривым планом для БД разработанной им же. Он значит притворяется разработчиком БД если так.
A>>Эти операции тебе понадобятся в любом случае. Никаких лишних сущностей тут нет. C>Есть. Я могу выкинуть кучу ручного труда с помощью разных автоматических байндеров и валидаторов.
Ты не можешь с помошью байндеров и валидаторов избежать неоптимизированного конечного SQL запроса. SQL запросы пишутся руками и я за то чтобы из писали только квалифицированны кадры, а не все подряд по мере надобности.
C>Если DBA знает только SQL — то он не сможет понять ТЗ, написаное аналитиком. Так что возможны два варианта:
Вполне сможет, если оно написано на уровне Entity-Relations.
C>1. Аналитик дает задание девелоперам, те рисуют черновую схему базы данных (я это делаю прямо в коде, из которого автоматически строится схема). Эта схема с комментариями отдается DBA, который ее оптимизирует (расставляет нужные индексы, ставит дополнительные проверки, может денормализует что-нибудь). Оптимизированая схема отдается обратно девелоперам, которые подправляют под нее код (обычно требуется править совсем немного).
Это порочная практика. Рядовой разработчик никогда не сможет придумать действительно удачную схему хранения данных в БД. DBA должен плясать не от объектной модели, а от ER-диаграммы. В описанном тобой сценарии DAL скорее всего выродится, так как БД будет отображать иерархию объектов, а не хранимые данные. Подкрутить индексы и денормализовать чего-нибудь это далеко не самое главное в разработке схемы. Есть данные которые в реляционную модель, порой, просто не укладываются как есть и их надо преобразовывать до неузнаваемости.
C>2. Аналитик дает задание DBA. DBA рисует схему и отдает ее программистам. Программисты по схеме строят DAL.
Хороший сценарий, мой любимый. Я получаю качественный продукт от человека, не сбитого с толку чьими-то неуместными ОО-идеями.
C>Случай когда тебе дают готовую схему БД означает, что приложение уже скорее всего было написано и работает. Тогда ничего не мешает тебе дать и готовый слой DAL (в виде отдельного модуля). Просто очень часто как раз делают псевдо-DAL на хранимках.
Нет, я всегда по мере возможности настаиваю чтобы БД разрабатывалась в первую очередь.
A>>Это совсем другая транзакция, не надо путать тёплое с мягким. Если например, надо статью из категории "Разное" перенести в категорию "Юмор", то разумно на уровне БД в виде ХП реализовать MoveArticle объединяющую DELETE И INSERT в транзакцию, чтобы статья не подвисла без категории (и не оказалась сразу в двух). А вот уже в бизнес-транзакции можешь объединить массовый перенос статей в нечто болеее высокоуровневое, но INSERT И DELETE должны быть объеденены на уровне БД. C>Хороший пример. А если у нас нет операции MoveArticle? Как ты в случае БД
Ты кажется не дописал вопрос. Во всяком случае он выглядит недописанным.
C>Процедуры DAL в виде selectByLogin/updatePassword замечательно пишут обычные программисты, точнее это все замечательно автоматизируется. Если их переложить на DBA — то он просто завязнет в куче мелких запросов (видел такое собственными глазами далеко не раз), да еще и проблемы с версированием БД начнутся.
ХЗ, у меня не завязают. Мои выносливее?
C>На откуп DBA остаются только оптимизации сложных запросов и всякие сложные операции, требующие временных таблиц, километровых запросов и кувырков с переворотами. Вот тут, кстати, ХП как раз вполне подходят.
Это DBA-лентяи какие-то. Напрограммил то, что было самому интересно, а на остальное плюнул, путь негры пашут Безответственно Почему именно — ниже (пометил знаком %).
C>Вот ты мне привел пример с XP для операций с User'ом. Не вижу там ни одного нетривиального SQL-оператора, который не смогу написать бы даже студент. Зачем тогда заставлять высококвалифицированного DBA заниматься этой ерундой?
Высококвалифицированного вероятно незачем, но даже такой ерундой кто-то должен заниматся не по мере надобности, а в соответствии с генеральным планом, потому что даже в такой ерунде можно наломать дров.
C>А если мы даем программистам писать/править свои ХП — то тогда они уже у нас скорее всего не полные идиоты, неспособные понять даже простого SQL UPDATE.
% (пометка, которую ты ждал)
Проблема в том, что этот простой SQL UPDATE в деномализованной для чего-то там БД может разрушить целостность данных. DBA знает (помнит, записал, пометил для себя крестиком на пальце) что таблица денормализована и что обновив тут, надо ещё подкрутить там (кстати опять транзакция уровня БД, без неё никак). Рядовой программист этого не знает и может напортачить. А раз может, значит обязательно напортачит. Считай это законом Мерфи.
DBA не тормозит разработку как ты пытаешь представить, он не злой дядя-тормозун. Просто изменения большой системы с сохраненим её согласованности это конечно же куда более сложный и длительный процесс, чем написание "с нуля" как надо. Да, добавить столбец в таблицу оставив все запросы целостными может оказатся не просто. Но пусть этим занимается один человек, а иначе будут "сюрпризы".
Здравствуйте, adontz, Вы писали:
Поддерживать код SQL проще? Не смешите мои тапочки. Если у вас сидит один монстр который с уцтра до вечера фигачит запросы и у которого в голове лежит вся схема базы со всеми хранимками, то я понимаю почему Вы так говорите. А теперь предположитеЮ, что проходят годы, код меняется, дописывается новый. В один прекрасный день происходит непредвиденная ситуация — Ваши монстры SQL уходят, а новым надо уйму времени, что бы осознать какие хранимки что делают и как внести изменение, не поломав что то в другом конце системы. Не говоря уж о том, что бизнес логика должна оперировать понятиями бизнес логиками а не "математическими основами БД". А уж если в один прекрасный день вам предложат мигрировать с MS SQL на Oracle то Вы совсем расстроитесь.
Re[8]: Оформление работы с БД в корпоративных приложениях -
Очень странно видеть такую полемику, напоминает религиозные войны программистов на билдере и визуал си. Одним удобно пользоваться неким конструктором, который от них "прячет" (упрощает — кому как нравится) некоторые вещи; другим приятнее сделать всю черновую работу самим и быть увереными, что они не потеряли в производительности и контролируют процесс. В данном случае одни привыкли при работе с базой пользоваться промежуточными автоматизироваными средствами и думают, что это лучший вариант потому что привыкли работать имено в этом русле, другие также привыкли работать через хранимки и считают это вполе нормальным, и работа у них построенна изходя из этой особенности. Если работа организована грамотно, то можно работать в соответсвии с обоими идеями. Если где-то есть просчеты, то в любом случае будут проблемы, какой путь невыбери.
З.Ы.
Странно видеть возглассы о том, что большую бд с кучей хранимок тяжело поддерживать... Хочется задать вопрос, а большой проект с кучей разнородных классов легко подерживать?
Re[9]: Оформление работы с БД в корпоративных приложениях -
Здравствуйте, ilvi, Вы писали:
I>Странно видеть возглассы о том, что большую бд с кучей хранимок тяжело поддерживать... Хочется задать вопрос, а большой проект с кучей разнородных классов легко подерживать?
Код с классами подвергается чёткому структурированию и рефакторингу. Скрипты sql по своей природе плохочитаемы и не особо структурируются.
Re: Оформление работы с БД в корпоративных приложениях - как
Здравствуйте, Kazna4ey, Вы писали:
K>1) Изменение схемы БД...
Уже сказали. Либо ORM, либо еще что-то, но обязательно выделенный слой доступа к данным.
K>2) Смена СУБД. No comments.
Это все теория. На практике, например, перейти с SQL Server на Oracle довольно непросто.
K>Вопрос в том какой метод наиболее эффективен и распространен при разработке корпоративных приложений среднего размера (под средним размером я понимаю пару десятков тысяч строк кода написанного вручную и БД из пары десятков таблиц)?
Написание большой части таких запросов прекрасно автоматизируется.
K>Если какое-то обращение к БД — единичное, т.е. запрос очень специфический и его вызов происходит только в одном месте программы, то я не отделяю его от кода формы, т.е. пишу его прямо в обработчике события или отдельным методом класса формы/контрола, например так:
Обрывать руки
K>Пока писал пример, возник попутный вопрос: K>Насколько нужно/ненужно использовать хранимые процедуры/функции?
Лично мое ХО -- я в общем случае против.
K>Если запрос или его модификация должен вызываться из нескольких мест в программе, то я его оформляю в виде статического метода в классе типа CommonFuncs:
Класс CommonFuncs, я так понимаю, раздувается до совешенно неприличных объемов? Плохо. Статические методы тоже плохо. Хотя бы потому, что код, их использущий, очень тяжело тестировать.
K>Если работа происходит с таблицей (всмысле гридом) обычно стараюсь работать через SelectCommand, UpdateCommand и т.д. класса SqlDataAdapter, типа так:
strSQL = "SELECT blablabla FROM parts WHERE Customer = ?Customer AND OrderDebited = true AND " +
"OrderInvoiced = false AND IsScanned = ?IsScanned AND IsPacked = ?IsPacked ORDER BY ManufacturerID, PartN";
Про запросы в коде см. пункт 1.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
HgLab: Mercurial Server and Repository Management for Windows