繁体   English   中英

如何在带有 Yii 框架的 oracle 11g 中使用 CLOB

[英]How to use CLOB in oracle 11g with Yii framework

我将 Yii 中的对象映射到包含一个 CLOB 列的表。

如何使用 save() 方法调用一个 ~54k 字符长度的字符串插入一行?

Yii 在它的 ActiveRecord 模型中有 beforeSave() 和 afterSave() 事件方法。 我会使用它们而不是覆盖 save() 方法。 将所有必要的 Oracle 方法放在那里。 基本上:清空 beforeSave() 中的字段,然后在 afterSave() 中使用 OCIParse() 等将值写入 DB。

这是一篇关于使用 Cake PHP 框架的很好的博客文章,它非常相似(MVC 与前后保存方法)。 显然,您将需要修改此代码以使用 Yii,但它应该让您走上正轨:

http://nik.chankov.net/2008/01/03/cakephp-and-oracle-handling-clob-fields/

最新版本的 Yii 现在也有一个查询构建器,这可能对您需要编写的 afterSave() 代码有一些帮助:

http://www.yiiframework.com/doc/guide/1.1/en/database.query-builder

祝你好运!

我刚刚解决了。 我还需要在 oracle 11g 中使用 BLOB,我想将图像插入到 oracle 表中。

我在网上搜索它,最后我在此处输入链接描述找到了一个可能的解决方案。

请点击它。

我按照示例 #2

<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // some function to allocate a new ID

// assume that we are running as part of a file upload form
// You can find more information in the PHP documentation

$fp = fopen($_FILES['file']['tmp_name'], 'rb');

$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);

$db->beginTransaction();
$stmt->execute();
$db->commit();
?>

我得到 $db

$db = Yii::app()->db->getPdoInstance() 

代替

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');

其他的都一样。

祝你好运!

这对我有用,但我几乎没有表扬,我正在开始 MySQL 到 ORACLE 的适配。 疯狂的!!!

这是一个测试版,如果可以改进它将会有所帮助。

覆盖Model中的__get函数。

Entidad 类扩展 \common\myclass\MyActiveRecord {......

public function __get($name) {

    $columna = $this->getTableSchema()->getColumn($name);
    $current = parent::__get($name); 
    if (isset($columna->dbType) && $columna->dbType=='CLOB') {          
        if (is_string($current)) {
            return $current;
        } 
        else if (is_null($current)) {
            return $current;
        }
        else if ($this->isAttributeChanged($name)) {
            return $this->getAttribute($name);
        }
        else {
            $valor = stream_get_contents($current);   
            $this->setAttribute($name,$valor);
            return $this->getAttribute($name);                
        }
    } else {            
        return $current;
    }

}

.....

}

我们的项目在使用 yii2 和 Oracle DB 时也存在读写 LOB 字段的问题。 因此,此刻,我决定写一个类来覆盖 yii2 中 ActiveRecord 类的一些方法,并继承一些模型,而不是从 ActiveRecord 继承。 我让它比较通用,你可以作为你改进的基础https://github.com/pivasikkost/yii2-improvements/blob/master/models/ActiveRecordOciLob.php

<?php

namespace app\models\system;

use Yii;
use \yii\db\ActiveRecord;
use \yii\db\Query;

/**
 * ActiveRecordOciLob is the base class for classes representing relational data in terms of objects,
 * that should work correctly with LOB data in Oracle DB. Used Oci8Connection (in my case - neconix\src\Oci8Connection).
 * 
 * Just inherit your gii generated model class not from ActiveRecord, but from this class,
 * set $clob_attributes, $blob_attributes and $dbOciLobName to work.
 * 
 * @property array $clob_attributes an array of attribute names of the form "['name_1', 'name_2', ...]"
 * @property array $blob_attributes an array of attribute names of the form "['name_1', 'name_2', ...]"
 * @property array $primaryKeyOciLob an array of attribute names of the form "['name_1', 'name_2', ...]"
 * @property string $dbOciLobName Oci8Connection name
 * 
 * @author Konstantin Zosimenko <pivasikkost@gmail.com>
 * @since 2.0
 */
class ActiveRecordOciLob extends ActiveRecord
{
    // METHOD 4. Almost completed, it works!
    
    public static $clob_attributes = [];
    public static $blob_attributes = [];
    public static $dbOciLobName;
    public $primaryKeyOciLob; // Not static! for some reason, being static, when saving one descendant of this class from another descendant of this class, this variable is overwritten and takes the wrong value
    
    /** 
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        $this->primaryKeyOciLob = static::primaryKey();
    }
    
    /**
     * @return \yii\db\Connection the database connection used by this AR class.
     */
    public static function getDbOciLob()
    {
        return static::$dbOciLobName 
                ? Yii::$app->get(static::$dbOciLobName)
                : static::getDb()
        ;
    }
    
    /**
     * Override ActiveRecord afterFind() method to fix LOB data receiveing
     * Maybe it's better to do this in populateRecord() method
     * 
     * @inheritdoc
     */
    public function afterFind ()
    {
        // Get lob fields as string, because standardly ActiveRecord gets them as resource
        $lob_attributes = array_merge(static::$clob_attributes, static::$blob_attributes);
        
        $where = [];
        foreach ($this->primaryKeyOciLob as $attribute) {
            $where[$attribute] = $this->$attribute;
        }

        foreach ($lob_attributes as $lob_attribute) {
            //$this->$lob_attribute = stream_get_contents($this->$lob_attribute); // Does not work, for some reason always returns 1 value if you try to get multiple records
            $this->$lob_attribute = (new Query())
                ->select($lob_attribute)
                ->from(static::tableName())
                ->where($where)
                ->createCommand(static::getDbOciLob())
                ->queryScalar();
            $this->setOldAttribute($lob_attribute, $this->$lob_attribute);
        }
        
        parent::afterFind ();
    }
    
    /**
     * Override ActiveRecord update() method to fix LOB data update
     * 
     * @inheritdoc
     */
    public function update($runValidation = true, $attributeNames = null)
    {   
        if ($runValidation && !$this->validate($attributeNames)) {
            Yii::info('Model not updated due to validation error.', __METHOD__);
            return false;
        }
        
        if (!$this->beforeSave(false)) {
            return false;
        }
        
        $db = static::getDbOciLob()->getDbh();
        $fields_blob = static::$blob_attributes;
        $fields_clob = static::$clob_attributes; // array with the fields to be updated
        $fields_dirty = $this->getDirtyAttributes($attributeNames); // changed fields with values
        $exist_fields_dirty_clob = array_values(
                array_intersect(array_keys($fields_dirty), $fields_clob)
        );

        
        if (empty($fields_dirty)) {
            $this->afterSave(false, $fields_dirty);
            return 0;
        }
        
        $set = [];
        $into = [];
        foreach ($fields_dirty as $name => $value) {
            if (in_array($name, $fields_clob)) {
                $set[] = $name . " = EMPTY_CLOB()";
                $into[] = ":" . $name;
            /*} elseif (in_array($name, $fields_blob)) {
                $set[] = $name . " = EMPTY_BLOB()";
                $into[] = ":" . $name;*/
            } else {
                $set[] = $name . " = :" . $name;
            }
        }
        $set_stmt = implode(", ", $set); // array to string to fill 'set' clause in the sql
        $where = [];
        foreach ($this->primaryKeyOciLob as $attribute) {
            $where[] = $attribute . "=" .$this->$attribute;
        }
        $where_stmt = implode(" AND ", $where);
        //$returning = implode(", ", array_merge($fields_clob, $fields_blob));
        $returning = implode(", ", $exist_fields_dirty_clob); // array to string to fill 'returning' clause in the sql
        $into_stmt = implode(", ", $into); // array to string to fill 'into' clause in the sql

        $sql = "UPDATE " . static::tableName() . "
                    SET " . $set_stmt . "
                    WHERE " . $where_stmt
        ;
        if ($returning && $into_stmt) {
            $sql .= " RETURNING " . $returning . "
                    INTO " . $into_stmt
            ;
        }
        
        $stmt  = oci_parse($db, $sql);
        $my_lob = [];
        // just see http://www.oracle.com/technology/pub/articles/oracle_php_cookbook/fuecks_lobs.html
        // you'll get it i'm sure
        foreach ($into as $key => $value) {
            $my_lob[$key] = oci_new_descriptor($db, OCI_D_LOB);
            oci_bind_by_name($stmt, $value, $my_lob[$key], -1, OCI_B_CLOB);
            //oci_bind_by_name($stmt, $value, $my_lob[$key], -1, OCI_B_BLOB);
        }
        foreach ($fields_dirty as $name => $value) { // don't use $value in oci_bind_by_name! the link inside this variable is changing
            if (!in_array($name, $fields_clob)) {
                oci_bind_by_name($stmt, ":".$name, $fields_dirty[$name]);
            }
        }
        $result = oci_execute($stmt, OCI_DEFAULT); // or die ("Unable to execute query\n"); //echo oci_error()
        if ($result === false) {
            oci_rollback($db);
            return false;
        }
        if ($exist_fields_dirty_clob) {
            foreach ($exist_fields_dirty_clob as $key => $name) {
                //if (!$my_lob[$key]->savefile( Yii::getAlias('@webroot/uploads/') . $model->files[0]->name )) {
                if (!$my_lob[$key]->save($this->$name)) {
                    oci_rollback($db);
                    return false; //die("Unable to update clob\n");
                }
            }
        }
        oci_commit($db);
        //$my_lob[$key]->free();
        oci_free_statement($stmt);
        oci_close($db); // not sure
        
        $changedAttributes = [];
        $oldArrtibutes = $this->getOldAttributes();
        foreach ($fields_dirty as $name => $value) {
            $changedAttributes[$name] = isset($oldArrtibutes[$name]) ? $oldArrtibutes[$name] : null;
            $this->setOldAttribute($name, $value);
        }
        $this->afterSave(false, $changedAttributes);
        
        return $result;
    }
    
    /**
     * Override ActiveRecord insert() method to fix LOB data insertion
     * 
     * @inheritdoc
     */
    public function insert($runValidation = true, $attributes = null)
    {
        //return parent::insert($runValidation, $attributes);
        
        if ($runValidation && !$this->validate($attributes)) {
            Yii::info('Model not inserted due to validation error.', __METHOD__);
            return false;
        }
        
        if (!$this->beforeSave(true)) {
            return false;
        }
        
        $db = static::getDbOciLob()->getDbh();
        //$fields_blob = static::$blob_attributes;
        $fields_clob = static::$clob_attributes; // array with the fields to be updated
        $fields_dirty = $this->getDirtyAttributes($attributes); // changed fields with values
        $fields_dirty_names = array_keys($fields_dirty);
        $exist_fields_dirty_clob = array_intersect(array_keys($fields_dirty), $fields_clob);
        
        $values = [];
        $into = [];
        foreach ($fields_dirty as $name => $value) {
            if (in_array($name, $fields_clob)) {
                $values[] = "EMPTY_CLOB()";
                $into[] = ":" . $name;
            /*} elseif (in_array($name, $fields_blob)) {
                $values[] = "EMPTY_BLOB()";
                $into[] = ":" . $name;*/
            } else {
                $values[] = ":" . $name;
            }
        }
        $fields_stmt  = implode(", ", $fields_dirty_names);
        $values_stmt  = implode(", ", $values);
        //$returning = implode(", ", $fields_clob + $fields_blob);
        $returning = implode(", ", $fields_clob);
        $into_stmt = implode(", ", $into);

        $sql = "INSERT INTO " . static::tableName() . "
                    (" . $fields_stmt . ")
                    VALUES(" . $values_stmt . ")
        ";
        if ($returning && $into_stmt) {
            $sql .= " RETURNING " . $returning . "
                    INTO " . $into_stmt
            ;
        }

        $stmt  = oci_parse($db, $sql);
        $my_lob = [];
        // just see http://www.oracle.com/technology/pub/articles/oracle_php_cookbook/fuecks_lobs.html
        // you'll get it i'm sure
        foreach ($into as $key => $value) {
            $my_lob[$key] = oci_new_descriptor($db, OCI_D_LOB);
            oci_bind_by_name($stmt, $value, $my_lob[$key], -1, OCI_B_CLOB);
            //oci_bind_by_name($stmt, $value, $my_lob[$key], -1, OCI_B_BLOB);
        }
        foreach ($fields_dirty as $name => $value) { // don't use $value in oci_bind_by_name!
            if (!in_array($name, $fields_clob)) {
                oci_bind_by_name($stmt, ":".$name, $fields_dirty[$name]);
            }
        }
        
        $result = oci_execute($stmt, OCI_DEFAULT); //or die ("Unable to execute query\n"); //echo oci_error()
        if ($result === false) {
            oci_rollback($db);
            return false;
        }
        if ($exist_fields_dirty_clob) {
            foreach ($fields_clob as $key => $name) {
                //if (!$my_lob[$key]->savefile( Yii::getAlias('@webroot/uploads/') . $model->files[0]->name )) {
                if (!$my_lob[$key]->save($this->$name)) {
                    oci_rollback($db);
                    return false; //die("Unable to update clob\n");
                }
            }
        }
        oci_commit($db);
        //$my_lob[$key]->free();
        oci_free_statement($stmt);
        oci_close($db); // not sure

        // Set primary key for new record
        $orderBy = [];
        foreach ($this->primaryKeyOciLob as $attribute) {
            $orderBy[$attribute] = SORT_DESC;
        }
        foreach ($this->primaryKeyOciLob as $attribute) {
            $fields_dirty[$attribute] = $this->find()
                ->orderBy($orderBy)
                ->limit(1)
                ->one()
                ->$attribute;
        }
        
        foreach ($fields_dirty as $name => $value) {
            $id = static::getTableSchema()->columns[$name]->phpTypecast($value);
            $this->setAttribute($name, $id);
            $fields_dirty[$name] = $id;
        }

        $changedAttributes = array_fill_keys(array_keys($fields_dirty), null);
        $this->setOldAttributes($fields_dirty);
        $this->afterSave(true, $changedAttributes);
        
        return $result;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM