Дефрагментация мозга. Софтостроение изнутри | страница 41



, позволяющий отловить некоторые ошибки на стадии компиляции.

Сравните выразительность языка на простом примере, который я оставлю без комментариев:


SQL

SELECT *

FROM task_queue

WHERE

id_task IN (2, 3, 15)

AND id_task_origin = 10


NHibernate HQL

IList queues = session

CreateQuery("from TaskQueue where Task.Id in (2, 3, 15) and TaskOrigin.Id = 10")

List();


NHibernate без HQL с критериями

IList queues = session.CreateCriteria()

Add(Expression.In("Task.Id", someTasks.ToArray()))

Add(Expression.Eq("TaskOrigin.Id", 10))

List();


LINQ (NHibernate)

IList queues = session

Query()

Where(q => someTasks.Contains(q.Task.Id) &&

q. TaskOrigin.Id == 10).ToList();


Внезапно оказывается, что собственный язык запросов генерирует далеко не самый оптимальный SQL. Когда БД относительно небольшая, сотня тысяч записей в наиболее длинных таблицах, а запросы не слишком сложны, то даже неоптимальный сиквел во многих случаях не вызовет явных проблем. Пользователь немного подождёт.

Однако запросы типа «выбрать сотрудников, зарплата которых в течение последнего года не превышала среднюю за предыдущий год» уже вызывают проблемы на уровне встроенного языка. Тогда разработчики идут единственно возможным путём: выбираем коллекцию объектов и в циклах фильтруем и обсчитываем, вызывая методы связанных объектов. Или используем тот же LINQ над выбранным массивом. Количество промежуточных коротких SQL-запросов к СУБД при такой обработке коллекций может исчисляться десятками тысяч.

Триггер как идеальная концепция для NHibernate

Обычно разработчикам баз данных я рекомендую избегать необоснованного использования триггеров. Потому что их сложнее программировать и отлаживать. Оставаясь скрытыми в потоке управления, они напрямую влияют на производительность и могут давать неожиданные побочные эффекты. Пользуйтесь декларативной ссылочной целостностью (DRI[58]) и хранимыми процедурами, пока возможно. А если ваш администратор баз данных склонен к параноидальным практикам «запрещено всё, что не разрешено», избегайте программировать на уровне СУБД, исключая критичные по производительности участки. Приходится говорить это с сожалением…

Однако стоит посмотреть на слой домена, живущего под управлением NHibernate, как становится ясно, что триггер в СУБД – это достаточно простая и хорошо документированная технология. В то время как NHibernate предлагает прикладному разработчику целый зоопарк триггероподобных решений.