Doctrine 自定义映射类型带来数据库错误

Doctrine custom mapping type brings database errors

我正在尝试使用自定义映射类型在 PostGis 中实现栅格功能。要将栅格添加到数据库,

我正在创建一个带有栅格类型列的 table。 要插入光栅数据,我要插入一个新的空光栅 st_makeemptyraster,添加一个新的波段 st_addband 并使用 st_setvalues.

设置值

所以,这可以在 PLAIN SQL 中以这种方式完成:

CREATE TABLE IF NOT EXISTS rasters (id serial, rast raster);
INSERT INTO rasters(id,rast)
VALUES(
    3, 
    st_setvalues(
        st_addband(     
            ST_MakeEmptyRaster( 2, 2, 0.0005, 0.0005, 1, 1, 0, 0, 4326),
            1,
            '32BF',
            1,
            0
        ),
        1,
        1,
        1,
        ARRAY[[9, 9], [9, 9]]::double precision[][]
     )
);

现在我尝试在 doctrine 中为栅格添加自定义映射类型。

我添加了实体光栅:

<?php
/**
 * More Documentation here:
 *
 * http://postgis.net/docs/manual-dev/RT_ST_MakeEmptyRaster.html
 *
 * raster ST_MakeEmptyRaster(raster rast);
 * raster ST_MakeEmptyRaster(integer width, integer height, float8 upperleftx, float8 upperlefty, float8 scalex, float8 scaley, float8 skewx, float8 skewy, integer srid=unknown);
 * raster ST_MakeEmptyRaster(integer width, integer height, float8 upperleftx, float8 upperlefty, float8 pixelsize);
 *
 *
 * http://postgis.net/docs/manual-2.2/RT_ST_AddBand.html
 *
 *
 */
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
use AppBundle\Model\Raster as RasterModel;
/**
 * Raster
 *
 * @ORM\Entity(repositoryClass="AppBundle\Entity\RasterRepository")
 * @ORM\Table(name="rasters")
 */
class Raster
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var RasterModel $raster
     *
     * @ORM\Column(name="rast", type="raster", nullable=true)
     */
    private $raster;
    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Set raster
     *
     * @param RasterModel $raster
     *
     * @return Raster
     */
    public function setRaster(RasterModel $raster)
    {
        $this->raster = $raster;
        return $this;
    }
    /**
     * Get raster
     *
     * @return Raster
     */
    public function getRaster()
    {
        return $this->raster;
    }
}

模型的php-对象:

<?php
namespace AppBundle\Model;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * Raster
 */
class Raster
{
    /**
     * @var Raster $raster
     */
    private $raster;
    /**
     * @var integer
     */
    private $width;
    /**
     * @var integer
     */
    private $height;
    /**
     * @var float
     */
    private $upperLeftX;
    /**
     * @var float
     */
    private $upperLeftY;
    /**
     * @var float
     */
    private $scaleX;
    /**
     * @var float
     */
    private $scaleY;
    /**
     * @var float
     */
    private $skewX;
    /**
     * @var float
     */
    private $skewY;
    /**
     * @var float
     */
    private $pixelSize;
    /**
     * @var integer
     */
    private $srid;
    /**
     * @var ArrayCollection RasterBand
     */
    private $bands;
    /**
     * Raster constructor.
     */
    public function __construct()
    {
        $this->bands = new ArrayCollection();
    }
    /**
     * @return Raster
     */
    public function getRaster()
    {
        return $this->raster;
    }
    /**
     * @param Raster $raster
     * @return Raster
     */
    public function setRaster($raster)
    {
        $this->raster = $raster;
        return $this;
    }
    /**
     * @return int
     */
    public function getWidth()
    {
        return $this->width;
    }
    /**
     * @param int $width
     * @return Raster
     */
    public function setWidth($width)
    {
        $this->width = $width;
        return $this;
    }
    /**
     * @return int
     */
    public function getHeight()
    {
        return $this->height;
    }
    /**
     * @param int $height
     * @return Raster
     */
    public function setHeight($height)
    {
        $this->height = $height;
        return $this;
    }
    /**
     * @return float
     */
    public function getUpperLeftX()
    {
        return $this->upperLeftX;
    }
    /**
     * @param float $upperLeftX
     * @return Raster
     */
    public function setUpperLeftX($upperLeftX)
    {
        $this->upperLeftX = $upperLeftX;
        return $this;
    }
    /**
     * @return float
     */
    public function getUpperLeftY()
    {
        return $this->upperLeftY;
    }
    /**
     * @param float $upperLeftY
     * @return Raster
     */
    public function setUpperLeftY($upperLeftY)
    {
        $this->upperLeftY = $upperLeftY;
        return $this;
    }
    /**
     * @return float
     */
    public function getScaleX()
    {
        return $this->scaleX;
    }
    /**
     * @param float $scaleX
     * @return Raster
     */
    public function setScaleX($scaleX)
    {
        $this->scaleX = $scaleX;
        return $this;
    }
    /**
     * @return float
     */
    public function getScaleY()
    {
        return $this->scaleY;
    }
    /**
     * @param float $scaleY
     * @return Raster
     */
    public function setScaleY($scaleY)
    {
        $this->scaleY = $scaleY;
        return $this;
    }
    /**
     * @return float
     */
    public function getSkewX()
    {
        return $this->skewX;
    }
    /**
     * @param float $skewX
     * @return Raster
     */
    public function setSkewX($skewX)
    {
        $this->skewX = $skewX;
        return $this;
    }
    /**
     * @return float
     */
    public function getSkewY()
    {
        return $this->skewY;
    }
    /**
     * @param float $skewY
     * @return Raster
     */
    public function setSkewY($skewY)
    {
        $this->skewY = $skewY;
        return $this;
    }
    /**
     * @return float
     */
    public function getPixelSize()
    {
        return $this->pixelSize;
    }
    /**
     * @param float $pixelSize
     * @return Raster
     */
    public function setPixelSize($pixelSize)
    {
        $this->pixelSize = $pixelSize;
        return $this;
    }
    /**
     * @return int
     */
    public function getSrid()
    {
        return $this->srid;
    }
    /**
     * @param int $srid
     * @return Raster
     */
    public function setSrid($srid)
    {
        $this->srid = $srid;
        return $this;
    }
    /**
     * @return ArrayCollection
     */
    public function getBands()
    {
        return $this->bands;
    }
    /**
     * @param ArrayCollection $bands
     * @return Raster
     */
    public function setBands($bands)
    {
        $this->bands = $bands;
        return $this;
    }
    /**
     * @param RasterBand $band
     * @return array|ArrayCollection
     */
    public function addBand(RasterBand $band)
    {
        $this->bands[] = $band;
        return $this->bands;
    }
    /**
     * @param RasterBand $band
     * @return $this
     */
    public function removeBand(RasterBand $band)
    {
        $this->bands->removeElement($band);
        return $this;
    }
}

自定义映射类型:

<?php
namespace AppBundle\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
class RasterType extends Type
{
    const RASTER = 'raster';
    public function getName()
    {
        return self::RASTER;
    }
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        return 'raster';
    }
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        /**
         * ToDo: Finish implementing it
         */
        return new \AppBundle\Model\Raster();
    }
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        return sprintf('%d, %d, %f, %f, %f, %f, %f, %f, %d', 10, 10, 0.1, 0.1, 0.1, 0.1, 0, 0, 4269);
    }
    public function canRequireSQLConversion()
    {
        return true;
    }
    public function convertToPHPValueSQL($sqlExpr, $platform)
    {
        /**
         * ToDo: Finish implementing it
         */
        return sprintf('AsText(%s)', $sqlExpr);
    }
    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
    {
        return sprintf('st_makeemptyraster(%s)', $sqlExpr);
    }
}

我的第一个意图是尝试向数据库中添加一个空栅格。 没有插入或更新栅格,而是出现以下错误:

2) AppBundle\Tests\Entity\RasterTest::testCreateEmptyRasterAndAddBand
Doctrine\DBAL\Exception\DriverException: An exception occurred while executing 'INSERT INTO rasters (id, rast) VALUES (?, ?)' with params [2, "st_makeemptyraster(10, 10, 0.100000, 0.100000, 0.100000, 0.100000, 0.000000, 0.000000, 4269)"]:

SQLSTATE[XX000]: Internal error: 7 ERROR:  rt_raster_from_wkb: wkb size (46)  < min size (61)

与普通 SQL 相同的数据 - 查询工作正常:

INSERT INTO rasters (id, rast) VALUES (14, st_makeemptyraster(10, 10, 0.100000, 0.100000, 0.100000, 0.100000, 0.000000, 0.000000, 4269)); 
INSERT 0 1

有人知道如何解决这个问题吗? 谢谢

(我的声望低于50是不能评论的,所以我只能写一个回答。有些mod可能会改成评论?)

我不熟悉 Doctrine,但首先我对一个常见问题有一个假设。

您能否确保在构建查询之前向任何查询传递值不会受到字符串转换的影响?执行带有参数的查询可能会将它们转换为带有转义字符的字符串值以避免安全问题。

一个例子:

$yourDoctrineAdapter->executeInsert( 42, "storedProcedureCall( 'foo' )" );

可能会导致类似

的结果

INSERT INTO foo ( bar, baz ) VALUES ( '42', 'storedProcedureCall( \'foo\' )' );

我的第二个假设是关于内部错误消息,而不是关于错误类型。

rt_raster_from_wkb: wkb size (46) < min size (61).

我不知道 st_makeemptyraster() 的 return 值是多少,但是你从 Doctrine 调用可能仍然会导致字符串参数而不是存储函数调用。列 rast 中插入的值被类型框化,然后字符串化 "call" 的 WKB 大小小于 st_makeemptyraster() 的存储函数 return 值的 WKB 大小。

我建议深入研究 'how to execute stored function calls with doctrine'。