将大型/复杂查询存储为OOP常量变量,最佳实践?

时间:2013-11-12 20:20:25

标签: php class oop

我的应用程序使用了一些非常大且复杂的SQL查询。我不想在使用它们的类中使用它们,因为它们会混乱。所以我尝试了一些新功能:将它们存储在Queries类中,并将我的应用程序使用的各种查询设置为该类中的const变量。然后,在我的其他类中,我将查询称为Db::query(Queries::queryID, array($parameter))。这会将查询的混乱存储在其他地方,并使工作类保持整洁。这也有助于减少重复,因为有多个类使用了一些查询。

示例:

abstract class Queries {

    const queryID = <<<'SQL'
SELECT t.typeID, t.typeName, ROUND(greatest(0,sum(t.quantity)) * (1 + (b.wasteFactor / 100))) * ? AS quantity
FROM
   (SELECT invTypes.typeid typeID, invTypes.typeName typeName, quantity 
    FROM invTypes, invTypeMaterials, invBlueprintTypes
    WHERE invTypeMaterials.materialTypeID = invTypes.typeID AND
          invBlueprintTypes.productTypeID = invTypeMaterials.typeID AND
          invTypeMaterials.TypeID = ?
    UNION 
    SELECT invTypes.typeid typeid, invTypes.typeName name, invTypeMaterials.quantity * r.quantity * - 1 quantity
    FROM invTypes, invTypeMaterials, ramTypeRequirements r, invBlueprintTypes bt 
    WHERE invTypeMaterials.materialTypeID=invTypes.typeID AND
          invTypeMaterials.TypeID =r.requiredTypeID AND
          r.typeID = bt.blueprintTypeID AND
          r.activityID = 1 AND 
          bt.productTypeID = ? AND 
          r.recycle = 1
   ) t
INNER JOIN invBlueprintTypes b ON (b.productTypeID = ?)
GROUP BY t.typeid, t.typeName
SQL;

...

}

这在大多数情况下运作良好,但我想知道其他人对于从工作类中分离查询的意见。有更好的方法吗?我是否对此进行了微观管理?

1 个答案:

答案 0 :(得分:2)

我使用了几种方法。 一个是包含执行查询并返回结果的方法的类。

另一个是封装单个查询的类,它包含一个返回查询数据的Execute方法。后者的优点是,当您需要更多查询时,您没有失控的类。这是每个查询的一个类。这也允许您在同一个类中对数据进行额外的预处理。它就像是您的数据工厂。

如果你有一个合适的自动加载器,拥有一个查询类的文件夹很容易维护和使用。

按要求提供一个例子:

class Query_User {

  function __construct($username)
  {
    $this->username = $username;
  }

  function execute() {
    // A piece of pseudo code to execute the query:
    $result = YourDatabase::Instance->QuerySingleObject(
      "SELECT * FROM users WHERE username = :username",
      array("username" => $this->username));

    // Example post-processing of the data before it is returned.
    $result->age = DateUtils::yearsBetween($result->birthdate, time());

    return $result;
  }
}

然后你就可以这样称呼它:

$user = new QueryUser('JohnDoe')->execute();

此方法的优点是类本身小而简单,只包含一个查询。但是它可以实现数据的附加修改,或者它可以执行几个查询并将结果合并为一个结果。

您还可以引入额外的功能,例如缓存一些使用频繁的查询的结果:

class Query_User {

  function __construct($username)
  {
    $this->username = $username;
  }

  function execute() {
    $key = get_class() . ',' . $this->username;
    // Assuming there is some cache class to cache on disk or into MemCache.
    $result = Cache::read($key);
    if ($result === false)
    {
      $result = $this->performQuery();
      Cache::write($key, $result);
    }
    return $result;
  }

  function performQuery() {
    // A piece of pseudo code to execute the query:
    $result = YourDatabase::Instance->QuerySingleObject(
      "SELECT * FROM users WHERE username = :username",
      array("username" => $this->username));

    // Example post-processing of the data before it is returned.
    $result->age = DateUtils::yearsBetween($result->birthdate, time());

    return $result;
  }
}

也许您甚至可以将缓存隔离到基类中,从而更容易在所有查询类中实现它。

我没有解释使用自动装载机,但这是一个常见的主题,并没有严格地与这个答案相关联。但是,它会让您的生活更轻松,因为您不必为要使用的每个查询类调用includerequire