2013-10-13 21 views
1

我有一个自定义的Magento模块与EAV结构。它可以创建,编辑,删除和列出项目。Magento自定义模块与数据库时EAV重复属性行saveAction()

当我编辑并保存一个项目时,属性值不会被数据库中的新值所取代。在管理员上,我看到了新的价值,但在数据库中,旧价值也存在。

我所看到的管理员用户:
- 项目编辑
- 从测试1 t检验2
更改名称 - 保存成功
- 现在,该项目的名称是Test 2

我看到在数据库内容:
- value_id,entity_type_id,attribute_id,STORE_ID,ENTITY_ID,价值
- 旧行:5,31,961,0,5,测试1
- 新行:6,31,961,0,5,试验2

在代码:

public function saveAction() 
{ 
    if ($postData = $this->getRequest()->getPost()) { 
     $model = Mage::getSingleton('mynamespace/model'); 

     $model->setData($postData); 

     if ($this->getRequest()->getParam('id')) { 
      $model->setId($this->getRequest()->getParam('id')); 
     } 

     try { 
      $model->save(); 

      Mage::getSingleton('adminhtml/session')->addSuccess($this->__('Item has been saved.')); 
      $this->_redirect('*/*/'); 

      return; 
     } 
     catch (Mage_Core_Exception $e) { 
      Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 
     } 
     catch (Exception $e) { 
      Mage::getSingleton('adminhtml/session')->addError($this->__('An error occurred while saving this item.')); 
     } 

     $this->_redirectReferer(); 
    } 
} 

我第一次一行。保存后我有两行,保存后我有三个... 为什么setData()或setName()函数不能覆盖/更新旧行?为什么它会创建新的行?我该如何解决它?

安装程序文件:

$installer = $this; 
$installer->startSetup(); 

$eavTableName = 'loremipsum/lorem'; 

$installer->addEntityType(
    'loremipsum_lorem', array(
     'entity_model' => $eavTableName, 
     'table'   => $eavTableName 
    ) 
); 

$installer->createEntityTables(
    $this->getTable('loremipsum/lorem') 
)->addIndex(
    $this->getIdxName(
     $eavTableName, 
     array('entity_id', 'attribute_id', 'store_id'), 
     Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE 
    ), 
    array('entity_id', 'attribute_id', 'store_id'), 
    array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE) 
); 

$this->addAttribute('loremipsum_lorem', 'name', array(
    'type'    => 'varchar', 
    'label'    => 'Name', 
    'input'    => 'text', 
    'class'    => '', 
    'backend'   => '', 
    'frontend'   => '', 
    'source'   => '', 
    'required'   => true, 
    'user_defined'  => true, 
    'default'   => '', 
    'unique'   => false 
)); 

$installer->endSetup(); 

回答

2

尝试重写_updateAttribute方法

protected function _updateAttribute($object, $attribute, $valueId, $value) 
{ 
    $table = $attribute->getBackend()->getTable(); 
    if (!isset($this->_attributeValuesToSave[$table])) { 
     $this->_attributeValuesToSave[$table] = array(); 
    } 

    $entityIdField = $attribute->getBackend()->getEntityIdField(); 

    $data = array(
     'entity_type_id' => $object->getEntityTypeId(), 
     $entityIdField  => $object->getId(), 
     'attribute_id'  => $attribute->getId(), 
     'value'    => $this->_prepareValueForSave($value, $attribute) 
    ); 
    if ($valueId) 
    { 
     $data['value_id'] = $valueId; 
    } 

    $this->_attributeValuesToSave[$table][] = $data; 

    return $this; 
} 

只有value_id被添加到$data阵列中(如果找到)。解决了这个问题。 此解决方案也可以在以下网址找到:http://code007.wordpress.com/2014/03/24/magento-rows-are-not-updated-in-custom-eav-model-tables/

2

它看起来像问题与缺失的唯一索引-_-

尝试添加一个唯一索引你的实体表(_INT,_varchar,_decimal。 ...)在下面的cols

entity_id, attribute_id, store_id 

我加入后,这些中的一个,它的工作对我来说

,如果你想解决您的安装脚本: 你需要创建/更新您Setup Class

的问题是在Mage_Eav_Model_Entity_Setup::createEntityTables功能,缺少唯一索引。将该功能复制到您的设置类中并添加

  ->addIndex(
       $this->getIdxName(
        $eavTableName, 
        array('entity_id', 'attribute_id', 'store_id'), 
        Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE 
       ), 
       array('entity_id', 'attribute_id', 'store_id'), 
       array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE)); 

进入eav_tables的创建语句。
之后创建的EAV表foreach循环应该是这样的:

/** 
    * Create table array($baseTableName, $type) 
    */ 
    foreach ($types as $type => $fieldType) { 
     $eavTableName = array($baseTableName, $type); 

     $eavTable = $connection->newTable($this->getTable($eavTableName)); 
     $eavTable 
      ->addColumn('value_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
       'identity' => true, 
       'nullable' => false, 
       'primary' => true, 
       'unsigned' => true, 
      ), 'Value Id') 
      ->addColumn('entity_type_id', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array(
       'unsigned' => true, 
       'nullable' => false, 
       'default' => '0', 
      ), 'Entity Type Id') 
      ->addColumn('attribute_id', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array(
       'unsigned' => true, 
       'nullable' => false, 
       'default' => '0', 
      ), 'Attribute Id') 
      ->addColumn('store_id', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array(
       'unsigned' => true, 
       'nullable' => false, 
       'default' => '0', 
      ), 'Store Id') 
      ->addColumn('entity_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
       'unsigned' => true, 
       'nullable' => false, 
       'default' => '0', 
      ), 'Entity Id') 
      ->addColumn('value', $fieldType[0], $fieldType[1], array(
       'nullable' => false, 
      ), 'Attribute Value') 
      ->addIndex($this->getIdxName($eavTableName, array('entity_type_id')), 
       array('entity_type_id')) 
      ->addIndex($this->getIdxName($eavTableName, array('attribute_id')), 
       array('attribute_id')) 
      ->addIndex($this->getIdxName($eavTableName, array('store_id')), 
       array('store_id')) 
      ->addIndex($this->getIdxName($eavTableName, array('entity_id')), 
       array('entity_id')) 
      ->addIndex(
       $this->getIdxName(
        $eavTableName, 
        array('entity_id', 'attribute_id', 'store_id'), 
        Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE 
       ), 
       array('entity_id', 'attribute_id', 'store_id'), 
       array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE)); 
     if ($type !== 'text') { 
      $eavTable->addIndex($this->getIdxName($eavTableName, array('attribute_id', 'value')), 
       array('attribute_id', 'value')); 
      $eavTable->addIndex($this->getIdxName($eavTableName, array('entity_type_id', 'value')), 
       array('entity_type_id', 'value')); 
     } 

     $eavTable 
      ->addForeignKey($this->getFkName($eavTableName, 'entity_id', $baseTableName, 'entity_id'), 
       'entity_id', $this->getTable($baseTableName), 'entity_id', 
       Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE) 
      ->addForeignKey($this->getFkName($eavTableName, 'entity_type_id', 'eav/entity_type', 'entity_type_id'), 
       'entity_type_id', $this->getTable('eav/entity_type'), 'entity_type_id', 
       Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE) 
      ->addForeignKey($this->getFkName($eavTableName, 'store_id', 'core/store', 'store_id'), 
       'store_id', $this->getTable('core/store'), 'store_id', 
       Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE) 
      ->setComment('Eav Entity Value Table'); 

     $tables[$this->getTable($eavTableName)] = $eavTable; 
    } 

如果您已经创建了实体,你不想重新安装/删除表,尝试这样的事情未经检验

在您的资源模型
//your entity types 
$entityTypes = array('datetime', 'decimal', 'int', 'text', 'varchar'); 
foreach($entityTypes AS $type){ 
    $connection->addIndex(
     $this->getTable('loremipsum/lorem') . '_' . $type, 
     $installer->getIdxName(
      $eavTableName, 
      array('entity_id', 'attribute_id', 'store_id'), 
      Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE 
     ), 
     array('entity_id', 'attribute_id', 'store_id'), 
     array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE) 
    ); 
} 
+0

谢谢,但唯一的索引对我的情况并没有影响到这个问题。我遵循你的指示,但问题是一样的。我根据你的回答扩展了我的问题。 – David

+0

ahh ok找到了问题。你将索引应用到你的主实体表中,这是错误的,你需要将它应用到实体表_int,_varchar等,我想我明确表示:)。我将以这种方式修改我的答案 –

+0

我厌倦了它,但是这个代码 - 在最后一个块中 - 不会添加唯一索引。我通过安装脚本函数“run”成功添加了唯一索引,但是当entity_id,attribute_id和store_id是唯一索引时,新行将覆盖最后一行。现在,当数据库中有更多项目时,只有一个项目具有属性,因为attribute_id是唯一的。在这种情况下,另一个项目不能具有相同的attribute_id,例如title属性。 – David