如何在Magento mysql数据库中存储/查询商店/特定于网站(或非全局)的产品属性?

The*_*Lee 3 mysql magento

首先,我知道我应该使用模型而不是直接使用数据库.话虽如此,有没有人知道Magento如何处理非全球产品属性?

我有2个网站core_website:Admin(website_id = 0)和主网站(website_id = 1).我还有两个商店core_store:Admin(store_id = 0)和Default Store View(store_id = 0).似乎产品(或类别?)属性是否在范围内是全局属性存储在catalog_eav_attribute.is_global.值0对应于"商店视图"的范围,值1对应于"全局",2对应于"网站".到现在为止还挺好.

现在,如果我想为所有产品获取特定于商店的属性的值,例如"name"(eav_attribute.attribute_id= 71; eav_attribute.backend_type='varchar'; catalog_eav_attribute.is_global= 0),您会认为我会这样做:

SELECT *
FROM catalog_product_entity_varchar
WHERE attribute_id = 71
AND store_id = 1
Run Code Online (Sandbox Code Playgroud)

但这没有任何回报.所有这些名称实际上都在store_id= 0 行中.据我所知,数据库中存储为store_id= 1 的唯一属性是'url_key'和'url_path'.那么Magento如何存储这些价值呢?Magento如何检索它们?

是否所有值最初(或者)都存储为store_id= 0作为一种默认值,直到需要存储与该值不同的值?当需要存储与admin值不同的特定于商店的值时,magento会创建一个store_id= 1 的新行(或者它是什么store_id)?

如果那样 - 或类似的东西 - 就是这种情况,那么Magento如何检索特定于商店的值?它检查catalog_eav_attribute.is_global首先是有问题的属性?如果它是非全局的,那么它可以先用store_id= 1 查询,如果没有返回任何内容,那么查询默认值store_id= 0?

我想我的主要问题是magento是如何实际做到的.其次,为什么magento这样做而不是用实际的store_id存储值?另外,如果我要编写查询,我应该同时查询store_id= 0和store_id= 1,并根据属性是否为全局以及是否存在store_id = 1的值来选择正确的值?

Mar*_*ius 8

你似乎想通了.至少你对如何完成工作有个好主意.
总结并确认您的怀疑:
所有属性值都存储在catalog_product_entity_*哪里*可以是以下任何一个:decimal, int, varchar, text, datetime取决于属性类型(backend_type).

还有其他表格可以保存与层级定价和图像相关的数据,但现在让我们离开.

属性表定义

每个表都包含以下列:

value_id       - just an increment id for the table
entity_type_id - the entity type id for the product (always the same)
attribute_id   - reference to the attribute
store_id       - reference to the store view
entity_id      - reference to the product
value          - actual value
Run Code Online (Sandbox Code Playgroud)

有这些列上唯一约束entity_id,attribute_id,store_id.这意味着对于一个产品和一个属性,您只能拥有一个商店视图的值.

现在你正确的部分.

store_id = 0表示存储的值是默认值.
如果没有为特定商店视图指定值(store_id> = 1),则将使用此值.
如果属性设置为global,则store_id = 0即使您有值,也将使用值for store_id = 1.

例子

要了解如何检索值,请将此代码放在某个文件中并运行它(确保平面目录已禁用 - 稍后将详细介绍,并确保首先使用创建应用程序的实例Mage::app()):

存储视图属性

$collection = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('name', 'some_name');
echo $collection->getSelect();
Run Code Online (Sandbox Code Playgroud)

上面的代码意味着我想要检索具有该名称的产品列表some_name.
与集合关联的SQL查询如下所示:

SELECT 
    `e`.*, 
    IF(at_name.value_id > 0, at_name.value, at_name_default.value) AS `name` 
FROM 
   `catalog_product_entity` AS `e` 
    INNER JOIN 
         `catalog_product_entity_varchar` AS `at_name_default` 
               ON (`at_name_default`.`entity_id` = `e`.`entity_id`) AND 
                  (`at_name_default`.`attribute_id` = '96') AND 
                  `at_name_default`.`store_id` = 0 
    LEFT JOIN 
          `catalog_product_entity_varchar` AS `at_name` 
               ON (`at_name`.`entity_id` = `e`.`entity_id`) AND 
                  (`at_name`.`attribute_id` = '96') AND 
                  (`at_name`.`store_id` = 1) 
WHERE 
    (IF(at_name.value_id > 0, at_name.value, at_name_default.value) = 'some_name')
Run Code Online (Sandbox Code Playgroud)

丑陋吧?
因为name属性(ID 96在我的情况)是一个存储视图范围属性(is_global= 0)的Magento与表连接的两倍catalog_product_entity_varchar(即保持所述一个name),用于当前存储器视图为detault商店视图(ID,一次和一次= 0).添加条件:

 IF(at_name.value_id > 0, at_name.value, at_name_default.value)
Run Code Online (Sandbox Code Playgroud)

因此,如果商店标识1没有值,请使用默认值.

全球归因

现在让我们看看如果我们按全局属性过滤会发生什么.

$collection = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('weight', '1');
echo $collection->getSelect();
Run Code Online (Sandbox Code Playgroud)

sql打印如下:

SELECT 
    `e`.*, 
    `at_weight`.`value` AS `weight` 
FROM 
    `catalog_product_entity` AS `e` 
     INNER JOIN 
         `catalog_product_entity_decimal` AS `at_weight` 
          ON (`at_weight`.`entity_id` = `e`.`entity_id`) AND 
             (`at_weight`.`attribute_id` = '101') AND 
             (`at_weight`.`store_id` = 0) 
WHERE 
     (at_weight.value = '1')
Run Code Online (Sandbox Code Playgroud)

因此catalog_product_entity_decimal,与商店id = 0 的表的单个连接.

网站属性

如果属性的范围website就像它对商店视图范围那样发生,因为Magento在保存产品时在当前网站中的每个商店视图的属性值表中创建一行.
如果您想尝试使用status上面示例中的属性.

扁平目录
我早些时候承诺过一些关于"平面目录"的解释.
出于性能原因,Magneto介绍了这个功能(我不记得版本).
基本上,cron运行(或者您可以手动运行)并将产品和类别的EAV方法转换为平面表.每个商店视图一个(商店ID = 0除外).
这意味着一个属性将转换为新表中的一列.调用新表catalog_product_flat_{store_view_id_here}.
当想要某些属性的值时,这避免了许多左/内连接.
但同样,出于性能原因,并非所有属性都作为列添加到平面表中(仅适用于产品.对于类别,所有属性都已添加).
只有后端标记的属性Use in product listing才会转换为列.
您可以从System->Configuration->Catalog->Frontend->Use Flat Catalog Product(或Use Flat Catalog Category)打开/关闭此功能.

即使打开,平面表也只在前端使用.后端仍然使用EAV方法.

结论
我的结论是,编写自己的查询几乎不可能直接从数据库中检索数据.您应该使用magento提供的模型和集合.它可以节省很多心理健康.

我希望我能为你做一些更清楚的事情.