避免独特约束与原则冲突的最佳方法是什么?


What is the best way to avoid unique constraint collisions with doctrine?

对SQL表使用顺序标识符的内部缺点是最终用户可能很容易遍历所有表。有时这是一个问题。

一种解决方案是为每一行创建一个非顺序id,这是不可猜测的。

显然,这个id必须是唯一的字段。我可以使用随机函数为每行生成唯一的id但它有可能与之前设置的id相冲突。如果它发生碰撞,最终用户会将其视为随机bug…

这里有一个简单的解决方案来克服这个问题:

$keyValid = false;
while(!$keyValid) {
    // Create a new random key
    $newKey = generateKey();
    // Check if the key already exists in database
    $existingPotato = $em->getRepository('Potato')->findOneBy(array('key' => $newKey));
    if (empty($existingPotato)) {
        $keyValid = true;
    }
}
// Hooray, key is unique!

每当我想要一个新的id时,它迫使我至少执行一个SELECT语句。

那么,有没有更好的、被广泛接受的解决方案来解决这个问题呢?

或者,是否存在一个优化的id长度,使碰撞概率可以忽略不计(对于一个3,000,000行表),使这个问题无关?

您可以添加自定义id生成策略来完成此操作。您可以通过创建扩展AbstractIdGenerator的类来实现它:

use Doctrine'ORM'Id'AbstractIdGenerator;
class NonSequencedIdGenerator extends AbstractIdGenerator
{
    public function generate('Doctrine'ORM'EntityManager $em, $entity)
    {
        $class  = $em->getClassMetadata(get_class($entity));
        $entityName = $class->getName();
        do {
            // You can use uniqid(), http://php.net/manual/en/function.uniqid.php
            $id = generateKey();
        } while($em->find($entityName, $id));

        return $id;
    }
}

然后在你的实体类中使用注释添加它:

/**
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="CUSTOM")
 * @ORM'CustomIdGenerator(class="NonSequencedIdGenerator")
 */
private $id;

但是如果你的generateKey没有返回唯一标识符,你应该检查它是否已经存在。为了避免这种情况,您还可以为实体中的主键使用UUID生成器。

/**
 * @ORM'Id
 * @ORM'Column(type="guid", unique=true)
 * @ORM'GeneratedValue(strategy="UUID")
 */
private $id;

如果你不喜欢这样,你可以创建一个新的使用uid_short的自定义id生成,并使用像这样的函数使其更短。

use Doctrine'ORM'Id'AbstractIdGenerator;
class UuidShortGenerator extends AbstractIdGenerator
{
    public function generate(EntityManager $em, $entity)
    {
        $conn = $em->getConnection();
        return $conn->query('SELECT UUID_SHORT()')->fetchColumn(0);
    }
}

这里的问题是我不认为它提供了完全的可移植性