【问题标题】:How to determine which properties from class should be included in an UPDATE dynamic query?如何确定类中的哪些属性应包含在 UPDATE 动态查询中?
【发布时间】:2015-01-26 23:07:31
【问题描述】:

图 1:这是一个示例模型类

class Games {
    public $id = 0;
    public $date = null;
    public $player1_id = 0;
    public $player2_id = 0;
    public $score = null;

    public function save(){
        if(empty($this->id)){
            // do INSERT here
        }
        else{
            // do UPDATE here  
        }
    }
}

图2:这是一个类的使用示例

// Save a new date to an existing game
$game = new Games;
$game->id = $input['id'];
$game->date = $input['date'];
$game->save();

如果基于figure2 执行UPDATE 查询,则player1_idplayer2_idscore 的值将被错误地覆盖为零/空值。因此,figure2 中的调用我需要一种从类内部确定某些属性未设置的方法,因此我可以动态地将 UPDATE 查询更改为仅更新数据库中的特定字段。还是我接近这个错误?

注意:我知道我可以使用单个 array 属性来保存所有字段(并使用 isset),但这感觉就像它打破了模型的重点,并且也非常特定于 PHP(在那个该解决方案不能很好地转移到其他语言,例如严格键入数组的 JAVA?)。我也意识到我可以做我认为 ORM 做的事情,并在执行更新之前进行初始 SELECT 查询(但这似乎非常低效!)

【问题讨论】:

  • 愚蠢的问题 - 你为什么要在图 2 中创建一个新的 Games 对象?
  • 哈哈!抱歉,让我更新一下……(忘记了$game->save(); 电话)
  • 你是对的,ORM 可以为你做到这一点。我建议你看看这些,它们会为你节省大量编写和更新样板代码或调试白痴错误的时间。
  • ORM 不太适合我的项目。另请参阅有关 ORM 是否适用于复杂项目的精彩帖子:stackoverflow.com/questions/7765070/redbean-orm-performance
  • 我确实使用类进行连接/准备/等。所有 DAL 的东西。

标签: php mysql oop dynamic-queries


【解决方案1】:
  1. 声明一个 PRISTINE 常数。尝试将其设置为您创建的对象的新实例,例如 new MyPristine。
  2. 在您的 Game 构造函数中,将所有字段设置为该常量。这是将它们标记为“未触及”的技巧。您可以使用反射(如 ReflectionClass($game)->getProperties() )循环所有这些
  3. 在保存之前,再次遍历字段并使用 PRISTINE 测试它们的值。如果不同,则需要更改。

此解决方案假设没有人/没有其他人会在第 2 步和第 3 步之间更改 Game 实例。这就是为什么大多数 ORM 会事先执行 SELECT。

【讨论】:

    【解决方案2】:

    在更新之前选择您的对象。这样,您的 UPDATE 语句将包含所有字段。

    此外,这可以让您检查 id 是否存在。

    【讨论】:

    • 所以每次我在构造函数中使用 ID 实例化对象时,我应该执行 SELECT 吗?我只是对添加额外的查询感到不安(不应该随意添加查询!)
    • 人们可以删除游戏吗?如果是这样,最好在运行所有更新逻辑之前检查您是否还有游戏。
    • 这使得我在 MySQL 中设置的唯一键约束是白费力气?如果我要在每次插入/更新之前通过 SELECT 查询执行约束检查。
    • 请记住,我可能会以 ON DUPLICATE KEY UPDATE 的形式一起执行 INSERT 和 UPDATE
    • 我不明白。唯一键约束就是这样:它们确保每个游戏对该列都有唯一的值。它与删除无关。
    【解决方案3】:

    否则,在普通 SQL 中你可以这样做:

    UPDATE games SET date = "2015-01-26", anotherField = $game->anotherField() WHERE id = $game->id;
    

    注意:这是伪代码。使用准备好的语句:http://php.net/manual/en/pdo.prepared-statements.php

    反射文档:http://php.net/manual/en/book.reflection.php

    【讨论】:

    • 这意味着我必须为每个变体编写单独的 SQL 语句(更新 1 个字段、更新 2 个字段、不同的组合等),不好。
    • 我以为您不想在每次更新视图时都更新 save() 方法,并且值是从表单中检索的,所以您总是会得到所有值。
    • 如果您不想使用 ORM,请使用黑魔法:1) 将所有字段设置为名为 UNSET 或 PRISTINE 的常量 2) 让某些内容更新您的对象 3) 循环遍历所有对象属性使用 new ReflectionClass($game)->getProperties(),如果该值不是 PRISTINE,则将其包含在您的 UPDATE 查询中。
    • Bob,我如何测试它是否设置为常数?请记住,该字段可以是零、null 或任何值。 isset(在数组元素上)是我认为我唯一可以使用的东西?
    • isset 不起作用?我没有想到。我正在考虑在默认构造函数(new Game;)中将所有值设置为那个 PRISTINE 常量,然后再进行比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    相关资源
    最近更新 更多