0

我的应用程序使用了一些非常大且复杂的 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;

...

}

这在大多数情况下运行良好,但我想知道其他人对像这样将查询与工作类分开的意见。有没有更好的方法?我在微观管理这个吗?

4

1 回答 1

2

I used a couple of methods. One is a class that contains methods that execute queries and return the results.

Another one is a class that encapsulates a single query and contains an Execute method that returns the queried data. The advantage of the latter is that you don't have a class that grows out of control when you need more queries. It's a class per query. That also allows you to put additional pre-processing of the data in that same class. It's like a factory for your data.

If you've got a proper auto loader in place, having a folder of query classes is quite easy to maintain and use.

Per request an example:

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;
  }
}

You can then just call it like this:

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

The advantage of this method is that the class itself is small and simple, containing only one query. But it can implement aditional modification of the data, or it can execute a couple of queries and combine the results into a single result.

You could also introduce extra functionality, like caching the results for some heavily used queries:

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;
  }
}

Maybe you could even isolate that caching into a base class, making it more easy to implement it in all your query classes.

I haven't explained the use of auto loaders, but that is a common subject and not strictly linked to this answer. It will make your life easier, though, since you don't have to call include or require for every query class you want to use.

于 2013-11-12T20:28:36.600 回答