第6章 商品属性.docx
- 文档编号:6239766
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:16
- 大小:924.09KB
第6章 商品属性.docx
《第6章 商品属性.docx》由会员分享,可在线阅读,更多相关《第6章 商品属性.docx(16页珍藏版)》请在冰豆网上搜索。
第6章商品属性
第6章 商品属性
很多在线商店允许购买者自定义他们购买的商品。
例如,在销售气球时,通常允许顾客自定义气球的颜色等。
本章中,我们将实现产品的属性特征,假定客户端允许顾客下订单时选择气球的颜色。
我们先从数据层开始,在数据层先创建一个数据表和存储过程,然后在业务层中调用该存储过程,最后使用这些功能来修改表示层的组件。
本章的结尾,将允许顾客选择气球的颜色,如图Figure6-1所示。
Figure6-1.Productswithattributes
6.1 实现数据层(ImplementingtheDataTier)
数据层组件支持产品属性特征,包含三个数据表(Attribute,AttributeValue,andProductAttributeValue)以及一个存储过程,名称为GetProductAttributeValues。
三个数据表如下:
•Attribute表存储属性的名称,例如Size或者Color。
•AttributeValue表包含可能的属性值。
在Attribute和AttributeValue数据表之间是一对多的联系。
每一个属性—例如Color—可能有多个和它相联系的值—Red,Orange,Yellow等等。
我们需要该数据表的目的是帮助我们建立从AttributeID(like1forColor)到其可能的值(Red,Orange,Yellow,andsoon)的AttributeValueIDs的链接。
所以,该数据表需要三个字段:
AttributeID对应于Attribute数据表,表示是哪一种属性(例如color或者size);AttributeValueID字段是integer类型,是唯一的标识列(uniquelyidentify);Value字段表示属性的描述文本,例如“Orange,”“Red,”“Small,”“Large,”等等。
•ProductAttributeValue是一个联系表的实现,对应于Product数据表AttributeValue数据表的多对多的联系,该数据表中有字段对(ProductID,AttributeValueID)。
要注意的是,应用不允许产品属性来影响产品的价格。
例如,一个白气球和一个黑气球的价格总是相等的。
若需要不同的产品价格,你需要创建不同的产品。
第5章中通过数据库图表理解了数据表之间的关系。
这些数据表之间的联系的可视化表示如图Figure6-2。
Figure6-2.Diagramdescribingtherelationshipsamongthedatatablesrequiredtoimplement
productattributes
下面我们修改BalloonShop数据库,然后通过练习实现一个新的存储过程CatalogGetProductAttributeValues。
练一练:
为产品属性创建数据层的功能
1.打开SQLServerManagementStudio并执行如下代码,该代码将创建并构造Attribute数据表(你也可以通过VisualWebDeveloper来创建存储过程)。
--ConnecttotheBalloonShopdatabase
USEBalloonShop
--Createattributetable(storesattributessuchasSizeandColor)
CREATETABLEAttribute(
AttributeIDINTIDENTITY(1,1)NOTNULLPRIMARYKEY,
NameNVARCHAR(100)NOTNULL--e.g.Color,Size
)
--PopulateAttributetable
SETIDENTITY_INSERTAttributeON
INSERTINTOAttribute(AttributeID,Name)
VALUES(1,'Color');
SETIDENTITY_INSERTAttributeOFF
注意:
我们使用SETIDENTITY_INSERTON(注意其中的下划线,原教材上没有),目的是在为数据表添加数据时,可以让我们自己来指定标识列的值。
除了此种情形之外,当一个字段是标识列(IDENTITY)字段时,数据库会为我们自动产生该标识列的ID值。
2.使用如下代码来创建并填充AttributeValuetable数据表:
--CreateAttributeValuetable(storesvaluessuchasYelloworXXL)
CREATETABLEAttributeValue(
AttributeValueIDINTIDENTITY(1,1)NOTNULLPRIMARYKEY,
AttributeIDINTNOTNULL,--TheIDoftheattribute
ValueNVARCHAR(100)NOTNULL--E.g.Yellow
)
--SettheIDENTITYINSERToptionforAttributeValue
SETIDENTITY_INSERTAttributeValueON;
--PopulateAttributeValuetable
INSERTINTOAttributeValue(AttributeValueID,AttributeID,Value)
SELECT1,1,'White'UNIONALL
SELECT2,1,'Black'UNIONALL
SELECT3,1,'Red'UNIONALL
SELECT4,1,'Orange'UNIONALL
SELECT5,1,'Yellow'UNIONALL
SELECT6,1,'Green'UNIONALL
SELECT7,1,'Blue'UNIONALL
SELECT8,1,'Indigo'UNIONALL
SELECT9,1,'Purple';
--SettheIDENTITYINSERToptionforAttributeValue
SETIDENTITY_INSERTAttributeValueOFF;
3.使用如下的代码创建并填充ProductAttributeValue数据表:
--CreateProductAttributeValuetable(associatesattributevaluesto
products)
CREATETABLEProductAttributeValue(
ProductIDINTNOTNULL,
AttributeValueIDINTNOTNULL,
PRIMARYKEY(ProductID,AttributeValueID)
)
--PopulateProductAttributeValuetable
INSERTINTOProductAttributeValue(ProductID,AttributeValueID)
SELECTp.ProductID,av.AttributeValueID
FROMproductp,AttributeValueav;
4.执行如下代码,该代码将创建外键并建立Figure6-2所示的数据表之间的联系。
--Createtheforeignkeys
ALTERTABLEAttributeValue
ADDCONSTRAINTFK_AttributeValue_Attribute
FOREIGNKEY(AttributeID)
REFERENCESAttribute(AttributeID)
GO
ALTERTABLEProductAttributeValue
ADDCONSTRAINTFK_ProductAttributeValue_AttributeValue
FOREIGNKEY(AttributeValueID)
REFERENCESAttributeValue(AttributeValueID)
GO
ALTERTABLEProductAttributeValueWITHCHECK
ADDCONSTRAINTFK_ProductAttributeValue_Product
FOREIGNKEY(ProductID)
REFERENCESProduct(ProductID)
GO
注意上面代码中的下划线,原教材中没有。
5.执行如下的SQL代码,将创建CatalogGetProductAttributeValues存储过程。
该存储过程将属性和一个产品相关联。
--CreateCatalogGetProductAttributeValuesstoredprocedure
CREATEPROCEDURECatalogGetProductAttributeValues
(@ProductIdINT)
AS
SELECTa.NameASAttributeName,
av.AttributeValueID,
av.ValueASAttributeValue
FROMAttributeValueav
INNERJOINattributeaONav.AttributeID=a.AttributeID
WHEREav.AttributeValueIDIN
(SELECTAttributeValueID
FROMProductAttributeValue
WHEREProductID=@ProductID)
ORDERBYa.Name;
解释该例是如何工作的:
产品属性的数据逻辑
我们将讨论创建并填充AttributeValue、ProductAttributeValue数据表以及CatalogGetProductAttributeValues存储过程的代码。
在讨论之前,确保你理解了Attribute,AttributeValue,和ProductAttributeValue数据表的每一个字段的含义以及填充这些数据表的代码。
我们先看看AttributeValue数据表。
为了填充该数据表,我们不是使用多个INSERT语句,而是使用INSERT...SELECT语句,该语句将允许我们插入由SELECT语句返回的结果。
然而,我们不是使用简单的SELECT语句来获取数据,我们使用了多个SELECT语句使用了UNIONALL。
总之,我们不是使用如下代码:
--PopulateAttributeValuetable
INSERTINTOAttributeValue(AttributeValueID,AttributeID,Value)
VALUES(1,1,'White');
INSERTINTOAttributeValue(AttributeValueID,AttributeID,Value)
VALUES(2,1,'Black');
INSERTINTOAttributeValue(AttributeValueID,AttributeID,Value)
VALUES(3,1,'Red');...
而是使用如下代码:
--PopulateAttributeValuetable
INSERTINTOAttributeValue(AttributeValueID,AttributeID,Value)
SELECT1,1,'White'UNIONALL
SELECT2,1,'Black'UNIONALL
SELECT3,1,'Red'UNIONALL...
如果你运行SQLServer2008,你可以使用更酷的方式来向数据表中插入多个值。
例如可以使用如下方式:
--PopulateAttributeValuetable--SQLSERVER2008syntax
INSERTINTOAttributeValue(AttributeValueID,AttributeID,value)
VALUES(1,1,'White'),(2,1,'Black'),(3,1,'Red'),...
当填充ProductAttributeValue数据表时,目的是想关联所有已存在属性值(通过AttributeValueID字段)到每一个产品(通过ProductID字段)。
在应用中,我们的产品是气球,我们想销售每一种可能颜色的产品。
填充ProductAttributeValue数据表的代码是使用INSERTINTO命令,该命令插入由SELECT查询得到的很多记录:
INSERTINTOProductAttributeValue(ProductID,AttributeValueID)
在我们的例子中,插入到ProductAttributeValue数据表的SELECT查询是一个交叉连接。
这种连接将产生两个集合的笛卡尔积(Cartesianproduct)。
结果是产生两个数据集的所有可能的组合。
例如,集合{1,2,3}和{a,b,c}的笛卡尔积,在数学上写为{1,2,3}×{a,b,c},将会产生如下的数据集:
{{1,a},{1,b},{1,c},{2,a},{2,b},{2,c},{3,a},{3,b},{3,c}}。
在我们的例子中,如果创建已存在的产品IDs值和已存在的属性值的IDs值的笛卡尔积,我们将获得形式为(ProductID,AttributeValueID)元素的列表,这就是我们想增加到ProductAttributeValue数据表中的记录。
实现该交叉连接的SQL语法是:
INSERTINTOProductAttributeValue(ProductID,AttributeValueID)
SELECTp.ProductID,av.AttributeValueID
FROMproductp,AttributeValueav;
例子数据中包含9个属性值和62个产品。
交叉连接操作将产生558(即9乘以62)条记录到ProductAttributeValue数据表中。
注意使用SELECT语句来创建交叉连接不是标准SQL,虽然这种形式为大多数数据库服务器认可。
正规的实现交叉查询的语法是使用CROSSJOIN语法:
INSERTINTOProductAttributeValue(ProductID,AttributeValueID)
SELECTp.ProductID,av.AttributeValueID
FROMproductpCROSSJOINAttributeValueav;
如果不使用交叉连接(crossjoin),我们也可以使用前面介绍的UNION方法。
UNION将多个SELECT语句的结果累加成一个单独的结果集。
例如,如果将两个各有5条记录的查询进行联合(UNION),结果集将有10条记录。
当然,对于UNION来说,所有的查询必须返回类型相容、数量相同的字段,我们在这里不将详细讨论UNION。
例如,使用UNION,你可以仅仅增加特定的属性值到产品中,如下面的代码所示:
--PopulateProductAttributeValuetable
INSERTINTOProductAttributeValue(ProductID,AttributeValueID)
SELECTProductID,1ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,2ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,3ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,4ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,5ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,6ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,7ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,8ASAttributeValueIDFROMproduct
UNIONALLSELECTProductID,9ASAttributeValueIDFROMproduct;
最后,我们看看存储过程CatalogGetProductAttributeValues。
该存储过程接受一个参数ProductID,并返回产品属性的列表。
--CreateCatalogGetProductAttributeValuesstoredprocedure
CREATEPROCEDURECatalogGetProductAttributeValues
(@ProductIdINT)
AS
存储过程中的SQL代码返回带有AttributeName,AttributeValueID,andAttributeValue的产品列表:
SELECTa.NameASAttributeName,
av.AttributeValueID,
av.ValueASAttributeValue
FROMAttributeValueav
INNERJOINattributeaONav.AttributeID=a.AttributeID
WHEREav.AttributeValueIDIN
(SELECTAttributeValueID
FROMProductAttributeValue
WHEREProductID=@ProductID)
ORDERBYa.Name;
你可以使用SQLServerManagementStudio来测试该存储过程,用值来替换参数的名字。
例如,你可以用一个产品的ID值来替换参数@ProductID,并执行该存储过程。
相应地,你也可以通过EXEC命令在SQLServerManagementStudio中执行存储过程(如下面的代码片段所示),或者右键点击存储过程在VisualWebDeveloper或者SQLServerManagementStudio中,并选择执行存储过程。
EXECCatalogGetProductAttributeValues1
该命令将返回具有产品ID值为1的结果。
如下图所示。
6.2 实现业务层(ImplementingtheBusinessTier)P207
实现业务层只需要编写调用CatalogGetProductAttributeValues存储过程的代码即可。
增加如下的代码到CatalogAccess类中,在App_Code/CatalogAccess.cs文件中。
//Retrievethelistofproductattributes
publicstaticDataTableGetProductAttributes(stringproductId)
{
//getaconfiguredDbCommandobject
DbCommandcomm=GenericDataAccess.CreateCommand();
//setthestoredprocedurename
comm.CommandText="CatalogGetProductAttributeValues";
//createanewparameter
DbParameterparam=comm.CreateParameter();
param.ParameterName="@ProductID";
param.Value=productId;
param.DbType=DbType.Int32;
comm.Parameters.Add(param);
//executethestoredprocedureandreturntheresults
returnGenericDataAccess.ExecuteSelectCommand(comm);
}
6.3 实现表示层(ImplementingthePresentationTier)
创建表示层的含义是增加相应的控件以允许用户从产品属性列表中选择相应的值。
属性值不是通过硬编码得到的,而是从数据库中读取的,这样在数据库中的属性值修改就可以直接反映到表示层中。
练一练:
实现产品属性表示层
1.将ProductsList.ascx中Price处的代码修改为如下:
Price:
<%#Eval("Price","{0:
c}")%>
PlaceHolderID="attrPlaceHolder"runat="server">
PlaceHolder>
2.增加如下的样式到BalloonShop.css文件中。
.DetailSection{
margin-top:
10px;
margin-bottom:
10px;
}
3.将ProductsList.ascx转换到DesignView,选择DataList控件,打开其属性窗口(使用F4快捷键)。
在属性窗口中选择事件图标,双击ItemDataBound事件实体。
4.增加如下的事件代码。
(注意需要导入System.Data名称空间,方法是在文件的开始位置使用usingSystem.Data;语句)。
usingSystem.Data;
//Executedwheneachitemofthelistisboundtothedatasource
protectedvoidlistItemDataBound(objectsender,DataListItemEventArgse)
{
//obtaintheattributesoftheproduct
DataRowViewdataRow=(DataRowView)e.Item.DataItem;
stringproductId=d
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第6章 商品属性 商品 属性