DRY и подобные запросы

Работая над конкретным приложением, я снова и снова пишу очень похожие запросы. Они не совсем одинаковы, но имеют очень похожую форму и встроены в почти идентичные фрагменты кода, например,,

$Mysqli = new mysqli;
if ($Stmt = $Mysqli->prepare("SELECT foo 
                              FROM tblFoo 
                              WHERE something = ?")) {
    $Stmt->bind_param('s', $this->_something);
    $Stmt->execute();
    if (0 != $Stmt->errno)
        throw new Exception("blah, blah, blah");
    $Stmt->bind_result($foo);
    while ($Stmt->fetch()){
        $this->_foos[] = new Foo($foo);
    }
    $Stmt->close();
    } else {
        throw new Exception("blah, blah, blah"););
    }
}

а потом еще где-то...

$Mysqli = new mysqli;
if ($Stmt = $Mysqli->prepare("SELECT bar, baz 
                              FROM tblBar 
                              WHERE somethingElse = ?")) {
    $Stmt->bind_param('s', $this->_somethingElse);
    $Stmt->execute();
    if (0 != $Stmt->errno)
        throw new Exception("blah, blah, blah");
    $Stmt->bind_result($bar, $baz);
    while ($Stmt->fetch()){
        // do something else with $bar and $baz
    }
    $Stmt->close();
    } else {
        throw new Exception("blah, blah, blah"););
    }
}

... а затем еще один, и в другом месте еще ... и т.д.

Является ли это реальным нарушением DRY? Кажется, нет смысла писать класс для выполнения такого рода запросов (с параметрами конструктора или сеттерами для таблицы, столбца, связанных переменных и т. д.), а затем повторно использовать его в моем приложении. Но в то же время я не могу избавиться от этого щемящего чувства, что я повторяюсь.

Может быть, дело в том, что существует очень много способов написать простой запрос, и следует ожидать определенного количества подобных повторений.

Мысли?


person PartialOrder    schedule 27.02.2009    source источник


Ответы (3)


Многие люди именно так и поступают. Создайте класс, представляющий каждую таблицу, все они наследуются от одного и того же класса. Базовый класс может обрабатывать загрузку и сохранение данных. Поэтому, если вы хотите загрузить данные, вы просто вызываете метод загрузки. И вы можете установить и получить доступ к значениям полей по свойствам объектов.

Существуют также такие библиотеки, как hibernate, которые сделают за вас большую часть грязной работы.

person Kibbee    schedule 27.02.2009
comment
@Кибби - Спасибо. Я не буду использовать Hibernate, но я создал класс ActiveRecord, а затем добавил пару классов для определенных таблиц. - person PartialOrder; 04.03.2009

Я бы сказал, что это было нарушением. Если взглянуть на ваш код (если я что-то не упустил), эти два утверждения идентичны, за исключением строк «foo» и «bar» (повторяющихся несколько раз) и вашей фактической бизнес-логики.

Как минимум, вы могли бы извлечь это. Более того, все строки SQL, вероятно, должны быть извлечены. Они всегда казались мне больше похожими на данные, чем на код. Если бы у вас был массив строк SQL, таблиц и т. д., сделал бы рефакторинг более очевидным?

(Извлечение строк и других данных из вашего кода — отличный способ начать рефакторинг)

Одна из возможностей: если у вас есть объект с именем таблицы и методом, содержащим вашу бизнес-логику, вы можете передать его в «Процессор» со всем шаблоном (то есть всем остальным кодом, который у вас есть).

Я думаю, что это может сделать его сухим.

(PS. Всегда предпочитайте композицию наследованию. Нет никакого преимущества в использовании наследования над классом, который может «запускать» ваши объекты)

person Bill K    schedule 27.02.2009
comment
@ Билл К. Это был близкий вызов, но я согласился с ответом Кибби, потому что он немного ближе к тому, как я на самом деле справился с этим. Ваши комментарии тоже были очень полезны, особенно об извлечении строк в качестве первого шага в рефакторинге. +1 спасибо! - person PartialOrder; 04.03.2009

Вы сталкиваетесь с одним из первых пожеланий модульности. :-)

Есть два общих решения. Первый — абстрагировать вызов всех (или большинства) похожих запросов. А потом снова к другому набору запросов. А потом к другому. И так далее. К сожалению, это приводит к многочисленным блокам, которые делают одно и то же: вызывают запрос, проверяют наличие проблем, собирают результирующий набор, передают его обратно. Это DAL, но только своего рода. Он также не масштабируется.

Второе решение состоит в том, чтобы абстрагировать процесс создания запроса и возврата результата, а затем рассмотреть абстрагирование доступа к данным поверх этого (что в основном означает, что вы создаете что-то, что собирает SQL). Это, скорее всего, станет правильным ORM, а не простым DAL. Это намного проще масштабировать.

person staticsan    schedule 27.02.2009