简体   繁体   English

当类DAO具有使用相同结果的方法时,减少查询数量的最佳方法是什么?

[英]What the best way to reduce the number of queries when the Class DAO have methods that use the same result?

I have a helper class DAO (I do not know if is OK have this) for get Categories from MySQL DB, the struct is basically this: 我有一个帮助类DAO(我不知道是否可以这样做),用于从MySQL DB获取Categories,该结构基本上是这样的:

<?php

require_once '../include/PDOConnectionFactory.php';

class CategoryDAO extends PDOConnectionFactory
{
    /**
     *
     * @var PDO $conn 
     */
    private $conn;

    public function __construct()
    {
        $this->conn = PDOConnectionFactory::getConnection();
    }
}
?>

This class have these methods (some then): 此类具有以下方法(然后是某些方法):

getMaxLevel()
getAllCategories()
getAllCategoriesOfLevel($level)
haveChildCategory($categoryName)
getIdCategory($categoryName)
getCategoryName($idCategory)

Edit : The body of the method getAllCategories() is similar to this below, and almost all method of this class call this getAllCategories(): 编辑 :方法getAllCategories()的主体类似于下面的内容,并且此类的几乎所有方法都将其称为getAllCategories():

public function method()
    {
        try {
            $stmt = $this->conn->prepare("SELECT * FROM category");
            $stmt->execute();
            $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            echo $e->getMessage();
        }

        return $result;
    }

I do not know what the best approach to reduce the redundancy of queries, I think in these: 我不知道减少查询冗余的最佳方法是什么,我认为:

  1. Instance the class object, call getAllCategories() and call the others methods passing the result by parameter. 实例化类对象,调用getAllCategories()并调用其他通过参数传递结果的方法。
  2. Have a private property with the result of getAllCategories(), populate when the objects is created by __construct(). 有一个私有属性,其结果为getAllCategories(),在由__construct()创建对象时进行填充。

But in these cases I see this drawback: 但是在这些情况下,我看到了这个缺点:

  1. Do not appear be a good use of OOP. 最好不要使用OOP。
  2. The object may be outdated after a DB UPDATE or INSERT. DB UPDATE或INSERT之后,该对象可能已过时。

If my problem is conceptual in OOP, please let me know. 如果我的问题在OOP中是概念性的,请告诉我。

Your DAO sounds like a really bad idea from the standpoint of efficiency. 从效率的角度来看,您的DAO听起来真是个坏主意。 Personally, I don't find Data Access Objects to provide any real value. 就我个人而言,我找不到提供任何真正价值的数据访问对象。 When would you pull a category name without also pulling its ID? 什么时候拉类别名称而不拉类别ID? You'd be better of querying for entire rows at a time and writing a few specialized queries to perform your other functions. 您最好一次查询整行,然后编写一些专门的查询来执行其他功能。

This response is dependent on the current query structure, where there are no conditionals 该响应取决于当前的查询结构,其中没有条件

class CategoriaDAO extends PDOConnectionFactory
{
    /*DB Connection, static member since you only need one connection*/
    private static $dbConnection;

    /*Sql result set, static since there is not conditonal and only a single table used*/
    private static $resultSet;

    private static function getConnection()
    {
            /*Connect to mysql db, set CategoriaDAO::dbConnection; */
    }

    private static function populateResultSet()
    {
            /*Run query and populate resultSet - either as sql result or parse to array - your call*/
    }
    /**
     *
     * @var PDO $conn 
     */
    private $conn;

    public function __construct()
    {
                /*Get sql connection if one hasn't already been established*/
                if(!CategoriaDAO::dbConnection)
                        $this->conn = PDOConnectionFactory::getConnection();
    }
}

The thought process behind this is that since the results will always be the same (ignore, update, insert, delete for now) there's no requirement to keep a copy of the results in each object. 其背后的思考过程是,由于结果始终是相同的(暂时忽略,更新,插入,删除),因此不需要在每个对象中保留结果的副本。

As you pointed out table updates will knock the stored result set out of sync with the object; 如您所指出的,表更新将使存储的结果集与对象不同步; this is where I'd like to back track a bit and say that if the result set for a given object only has to be up to date at the time of creation then use normal object members. 在这里,我想回溯一下,如果给定对象的结果集仅在创建时是最新的,则使用普通对象成员。

Also worth considering both independently and in conjunction with the previous comment is whether or not the query will change and if it will does it require object members to be generated. 值得一提的是,是否要更改查询以及是否更改查询,是否需要更改,都需要生成对象成员。 If the query doesn't change then there's nothing to worry about - except the previous point. 如果查询没有变化,那么除了前一点之外,没有什么可担心的。 If it does change your options are more or less covered in the following examples. 如果确实发生更改,以下示例将或多或少地涵盖您的选项。

class Foo{
    private $someMember;

    /*
        $params = Associative array of fields and values
    */
    private static buildAndRunQuery($params)
    {
        /*Build sql query based on the given params Array()*/
    }
    public __construct($someMemebrValue)
    {
        $this->someMember = $someMemberValue;
        Foo::buildAndRunQuery(Array("fieldName" => $this->someMember));
    }
}

In this example you're still using a static method to generate the query but you're passing non-static members for the process/ At this point (see comment on objects being up to date at time of creation) you can either store the results within the static member or pass them back to the __construct() function and store int he object instance. 在此示例中,您仍在使用静态方法来生成查询,但是您要为流程传递非静态成员/此时(请参阅有关创建时对象最新的注释),您可以存储静态成员中的结果,或将它们传递回__construct()函数并存储对象实例。

Then there's the potential that the query your using is a bit more involved than simply requesting certain fields such that creating a multidimensional array to pass to the static function would be more hassle than it's worth. 这样一来,您所使用的查询可能会比简单地请求某些字段要复杂得多,因此创建多维数组以传递给静态函数的麻烦将超过其价值。 In which case you might split the buildAndRunQuery() into buildQuery() - instance method and runQuery() static method such as. 在这种情况下,您可以将buildAndRunQuery()拆分为buildQuery()-实例方法和runQuery()静态方法,例如。

class Foo{

    private $someMember;

    /*
        $params = Associative array of fields and values
    */
    private static runQuery($query)
    {
        /*Build sql query based on the given params Array()*/
    }

    private function buildQuery()
    {
        /*Construct your query here and either return calling method or store in instance member*/
         /*Either*/
            return <Constructed query>;
        /*Or*/
           $this->query = <Constructed query>;
    }

    public __construct($someMemebrValue)
    {
        $this->someMember = $someMemberValue;
        /*As per buildQuery() comment either:*/
            Foo::runQuery($this->buildQuery());
        /*Or*/
            Foo::runQuery($this->query);
    }
}

In this case there are a couple of options for handling the generated query prior to calling Foo::runQuery(). 在这种情况下,在调用Foo :: runQuery()之前,有两个选项可以处理生成的查询。

Of course there's always the possibility that you don't want to create and run the query in a synchronous manner or indeed in the constructor. 当然,总有可能您不想以同步方式或实际上在构造函数中创建和运行查询。

In conclusion I personally feel that for methods that interact with services independent of the object itself such as Sql or perhaps focused DOMDocument, or similar, object interactions it is best to use Static methods where they are both relevant and not ultimately cutting off your nose to spite your face (needlessly complex etc). 总而言之,我个人认为对于与对象本身无关的服务进行交互的方法(例如Sql或可能的DOMDocument或类似的对象交互),最好在相关且不最终使您不知所措的情况下使用静态方法。讨厌你的脸(不必要地复杂等)。 Of course all of this needs to be considered on a per Class basis. 当然,所有这些都需要在每个班级的基础上加以考虑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM