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

时间:2014-02-25 19:31:08

标签: mysql magento

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

我在core_website中有2个网站:Admin(website_id = 0)和主网站(website_id = 1)。我在core_store中还有两个商店:Admin(store_id = 0)和默认商店视图(store_id = 0)。似乎产品(或类别?)属性是否属于全局范围存储在catalog_eav_attributeis_global中。值0对应于“商店视图”的范围,值1对应于“全局”,2对应于“网站”。到目前为止一切都很好。

现在,如果我想获取特定于商店的属性的值,例如“name”(eav_attributeattribute_id = 71; eav_attributebackend_type =' varchar'; catalog_eav_attributeis_global = 0)对于我的所有产品,你会认为我会做这样的事情:

SELECT *
FROM catalog_product_entity_varchar
WHERE attribute_id = 71
AND store_id = 1

但这没有任何回报。所有名称实际上都在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_attributeis_global是否有问题属性?如果它是非全局的,那么它可以先用store_id = 1进行查询,如果没有返回任何内容,则使用默认的store_id = 0进行查询?

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

1 个答案:

答案 0 :(得分: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

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

现在你正确的部分。

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

<强>实施例

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

商店视图属性

Mage::app()

上面的代码意味着我想要检索名为$collection = Mage::getModel('catalog/product')->getCollection() ->addAttributeToFilter('name', 'some_name'); echo $collection->getSelect(); 的产品列表 与集合关联的SQL查询如下所示:

some_name

丑陋吗? 因为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') 属性(在我的情况下为id 96)是商店视图范围属性(name = 0),Magento与表is_global(持有{{1}的表}连接两次}),一次用于当前商店视图,一次用于detault商店视图(id = 0)。添加条件:

catalog_product_entity_varchar

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

全球归属

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

name

sql打印如下:

 IF(at_name.value_id > 0, at_name.value, at_name_default.value)

因此,对于商店ID = 0,只需与表$collection = Mage::getModel('catalog/product')->getCollection() ->addAttributeToFilter('weight', '1'); echo $collection->getSelect(); 进行一次联接。

网站属性

如果属性范围为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') ,则所有操作都与商店视图范围相同,因为Magento在保存产品时在当前网站中的每个商店视图的属性值表中创建一行。
如果您想尝试使用上面示例中的属性catalog_product_entity_decimal

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

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

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

我希望我能让你的事情更加清晰。