如何确定类中的哪些属性应包含在 UPDATE 动态查询中?
Posted
技术标签:
【中文标题】如何确定类中的哪些属性应包含在 UPDATE 动态查询中?【英文标题】:How to determine which properties from class should be included in an UPDATE dynamic query? 【发布时间】: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_id
、player2_id
和score
的值将被错误地覆盖为零/空值。因此,figure2 中的调用我需要一种从类内部确定某些属性未设置的方法,因此我可以动态地将 UPDATE
查询更改为仅更新数据库中的特定字段。还是我接近这个错误?
注意:我知道我可以使用单个 array
属性来保存所有字段(并使用 isset
),但这感觉就像它打破了模型的重点,并且也非常特定于 php(在那个该解决方案不能很好地转移到其他语言,例如严格键入数组的 JAVA?)。我也意识到我可以做我认为 ORM 做的事情,并在执行更新之前进行初始 SELECT
查询(但这似乎非常低效!)
【问题讨论】:
愚蠢的问题 - 你为什么要在图 2 中创建一个新的 Games 对象? 哈哈!抱歉,让我更新一下……(忘记了$game->save();
电话)
你是对的,ORM 可以为你做到这一点。我建议你看看这些,它们会为你节省大量编写和更新样板代码或调试白痴错误的时间。
ORM 不太适合我的项目。另请参阅有关 ORM 是否适用于复杂项目的精彩帖子:***.com/questions/7765070/redbean-orm-performance
我确实使用类进行连接/准备/等。所有 DAL 的东西。
【参考方案1】:
-
声明一个 PRISTINE 常数。尝试将其设置为您创建的对象的新实例,例如 new MyPristine。
在您的 Game 构造函数中,将所有字段设置为该常量。这是将它们标记为“未触及”的技巧。您可以使用反射(如 ReflectionClass($game)->getProperties() )循环所有这些
在保存之前,再次遍历字段并使用 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 常量,然后再进行比较。以上是关于如何确定类中的哪些属性应包含在 UPDATE 动态查询中?的主要内容,如果未能解决你的问题,请参考以下文章