将自定义类型映射到多个列?

时间:2013-08-09 13:30:28

标签: mysql symfony doctrine-orm

我需要使用大型位掩码(~115位)。存储是mysql,我的orm是教义。在PHP方面,我写了一个类来处理任何事情并知道我需要一个很好的解决方案来存储并通过在MySQL中进行比较来再次找到它。我的想法是使用四个整数列或两个bigint。现在我需要一种映射(PHP Object< => 2-4 Columns DB)。我可以使用symfony2中的某些内容吗?

1 个答案:

答案 0 :(得分:0)

这不常做。很多时候会出现具有BIT类型的单列(或MySQL上的TINYINT)或将选项放在另一个表中并执行oneToMany(这将允许您的选项易于配置)。 Bitmasks更容易出错,因此请确保您真的需要此解决方案。话虽如此,这是如何做到的:

首先介绍MySQL数据类型的一些信息。对于无符号的位掩码,可能就是这样。

TINYINT -> 0-255 = 256 combinations = log 256 / log 2 = 8 bits
SMALLINT -> 16 bits
MEDIUMINT -> 24 bits
INT -> 32 bits
BIGINT -> 64 int

那么这些字段对115位的最佳使用是什么?这是NP完全问题,您可以使用贪心算法。采纳你的建议并使用4x INT和2x BIGINT。总共给出了256个可用位。这高于115位的要求。使用4x BIGINT 256位会更有意义。但是,我无法将这些列合并为一个大数字,而BIGINT甚至可能会出现问题。如PHP手册中所述:

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

为了安全(因为我不知道你的平台)我将只使用INT并使用其中四个给我128位。 (你仍然需要检查这对32位不支持无符号整数的问题是如何工作的!)

这是一个默认函数,doctrine:generate:实体会给你:public function getColumn1() {}然而,让其他对象访问这些原始的未处理数据似乎不是一个好主意。所以让我们为此制作自定义函数。

private function getBit($index) {
    if (0 <= $index AND $index <= 31) {
        return ($this->column1 >> $index) & 1;
    } elseif (32 <= $index AND $index <= 63) {
        $index -= 32;
        return ($this->column2 >> $index) & 1;
    } elseif (64 <= $index AND $index <= 95) {
        $index -= 64;
        return ($this->column3 >> $index) & 1;
    } elseif (96 <= $index AND $index <= 127) {
        $index -= 96;
        return ($this->column4 >> $index) & 1;
    }
}

private function setBit($index, $value) {
    if (! is_bool($value)) \BadMethodCallException('value needs to be a boolean'); // A form of type checking to make the interface to the function more clearly
    $value = (int)$value; // not sure if this is needed, just to make sure

    if (0 <= $index AND $index <= 31) {
        $this->column1 = ($this->column1 & ~(1 << $index)) | ($value << $index);
    } elseif (32 <= $index AND $index <= 63) {
        $index -= 32;
        $this->column2 = ($this->column2 & ~(1 << $index)) | ($value << $index);
    } elseif (64 <= $index AND $index <= 95) {
        $index -= 64;
        $this->column3 = ($this->column3 & ~(1 << $index)) | ($value << $index);
    } elseif (96 <= $index AND $index <= 127) {
        $index -= 96;
        $this->column4 = ($this->column4 & ~(1 << $index)) | ($value << $index);
    }
}

Column1用于最低有效位,其他列添加更多最高有效位。既然我们已经有了低级函数来处理原始位,那么就可以很容易地使用普通的getter和你想要的属性设置。

public function setFlag4($value) {
    $this->setBit(4, $value);
    return $this;
}

public function getFlag4() {
    return $this->getBit(4);
}

当然,您可以在第25位输入hasBananas()之类的任何名称而不是Flag4