原文:http://msdn2.microsoft.com/en-us/library/bb410047.aspx
BDC允许我们为特定的LOB(line-of-business)系统定义多个实体。而且,在元数据文件中,我们可以创建关联来定义实体间的层次关系。如,有两个实体的定义,customers和orders。我们可以创建关联将customer实体直接与order实体联系在一起。这样就可以允许用户在MOSS中创建并使用主子(master-child)行为。
本文将向大家介绍如何在MOSS中利用关联来过滤BDC数据。大家继续使用之前在介绍BDC实体创建的文章中使用的元数据文件。
- 在元数据文件中添加Sales Order实体
在已有的Customer实体元素下面添加下列内容。该XML定义了一个新的实体,名为SalesOrder。
< Entity Name ="SalesOrder" >
< Properties >
< Property Name ="Title" Type ="System.String" > salesordernumber </ Property >
</ Properties >
< Identifiers >
< Identifier Name ="SalesOrderID" TypeName ="System.Int32" />
</ Identifiers >
< Methods >
< Method Name ="GetSalesOrders" >
< Properties >
< Property Name ="RdbCommandText" Type ="System.String" >
SELECT
soh.salesorderid,
soh.orderdate,
soh.shipdate,
soh.status,
soh.salesordernumber,
soh.customerid
FROM
sales.salesorderheader soh
inner join sales.customer c
on soh.customerid = c.customerid
WHERE
c.customertype = 'i'
AND (soh.salesorderid > @minSalesOrderID AND
soh.salesorderid < @maxSalesOrderID)
</ Property >
< Property Name ="RdbCommandType" Type ="System.String" > Text </ Property >
</ Properties >
< Parameters >
< Parameter Direction ="In" Name ="@minSalesOrderID" >
< TypeDescriptor TypeName ="System.Int32" Name ="SalesOrderID"
IdentifierName ="SalesOrderID" >
< DefaultValues >
< DefaultValue MethodInstanceName =
"SalesOrderFinderInstance" Type ="System.Int32" > 0
</ DefaultValue >
< DefaultValue MethodInstanceName =
"SalesOrderSpecificFinderInstance" Type ="System.Int32" > 0
</ DefaultValue >
</ DefaultValues >
</ TypeDescriptor >
</ Parameter >
< Parameter Direction ="In" Name ="@maxSalesOrderID" >
< TypeDescriptor TypeName ="System.Int32" Name ="SalesOrderID"
IdentifierName ="SalesOrderID" >
< DefaultValues >
< DefaultValue MethodInstanceName =
"SalesOrderFinderInstance" Type ="System.Int32" >
9999999 </ DefaultValue >
< DefaultValue MethodInstanceName =
"SalesOrderSpecificFinderInstance" Type ="System.Int32" >
9999999 </ DefaultValue >
</ DefaultValues >
</ TypeDescriptor >
</ Parameter >
< Parameter Direction ="Return" Name ="SalesOrders" >
< TypeDescriptor TypeName ="System.Data.IDataReader, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=
b77a5c561934e089" IsCollection ="true" Name ="SalesOrderDataReader" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Data.IDataRecord, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
Name ="SalesOrderDataRecord" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Int32" IdentifierName =
"SalesOrderID" Name ="SalesOrderID" />
< TypeDescriptor TypeName ="System.DateTime" Name ="orderdate" />
< TypeDescriptor TypeName ="System.DateTime" Name ="shipdate" />
< TypeDescriptor TypeName ="System.String" Name ="status" />
< TypeDescriptor TypeName ="System.String" Name ="salesordernumber" />
< TypeDescriptor TypeName ="System.Int32" Name ="customerid" />
</ TypeDescriptors >
</ TypeDescriptor >
</ TypeDescriptors >
</ TypeDescriptor >
</ Parameter >
</ Parameters >
< MethodInstances >
< MethodInstance Name ="SalesOrderFinderInstance" Type ="Finder"
ReturnParameterName ="SalesOrders" />
< MethodInstance Name ="SalesOrderSpecificFinderInstance" Type ="SpecificFinder"
ReturnParameterName ="SalesOrders" />
</ MethodInstances >
</ Method >
</ Methods >
</ Entity > - 添加一个新的方法,基于CustomerID来过滤Orders
在SalesOrder实体中,已有的方法下面,添加一个新的方法,名为GetSalesOrdersForCustomer.。该方法包含了一个简单的SQL语句。特别值得注意的是WHERE语句,在这里通过customerID字段来进行过滤操作。另外,注意customerID的输入参数(@customerID),这里没有默认参数。该方法作为一个关联方法只有在用户选择了某个customer时才会被调用。
注:输入参数有一个IdentifierName属性和一个IdentifierEntityName属性与其关联。尽管这里我们在SalesOrder实体中使用customerID,但事实上customerID是Customer实体的标识符。BDC使用customer的标识符来获取选定的customer所对应的特定的sales orders。
< Method Name ="GetSalesOrdersForCustomer" >
< Properties >
< Property Name ="RdbCommandText" Type ="System.String" >
SELECT
soh.salesorderid,
soh.orderdate,
soh.shipdate,
soh.status,
soh.salesordernumber
FROM
sales.salesorderheader soh
inner join sales.customer c
on soh.customerid = c.customerid
where
c.customertype = 'i'
AND c.customerid = @customerID
</ Property >
< Property Name ="RdbCommandType" Type ="System.String" > Text </ Property >
</ Properties >
< Parameters >
< Parameter Direction ="In" Name ="@customerID" >
< TypeDescriptor TypeName ="System.Int32" Name ="CustomerID" IdentifierEntityName =
"Customer" IdentifierName ="CustomerID" >
<!-- Note that we don't have any default values for this. -->
<!-- Also, note the IdentifierEntityName attribute referes to the customer entity. -->
</ TypeDescriptor >
</ Parameter >
< Parameter Direction ="Return" Name ="SalesOrders" >
< TypeDescriptor TypeName ="System.Data.IDataReader, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=
b77a5c561934e089" IsCollection ="true" Name ="SalesOrderDataReader" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Data.IDataRecord, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=
b77a5c561934e089" Name ="SalesOrderDataRecord" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Int32" IdentifierName =
"SalesOrderID" Name ="SalesOrderID" />
< TypeDescriptor TypeName ="System.DateTime" Name ="orderdate" />
< TypeDescriptor TypeName ="System.DateTime" Name ="shipdate" />
< TypeDescriptor TypeName ="System.String" Name ="status" />
< TypeDescriptor TypeName ="System.String" Name ="salesordernumber" />
</ TypeDescriptors >
</ TypeDescriptor >
</ TypeDescriptors >
</ TypeDescriptor >
</ Parameter >
</ Parameters >
</ Method > - 在SalesOrder实体和Customer实体间定义关联
添加下面的XML到LobSystem元素的结尾(在结束标记</Entities>后)。GetSalesOrdersForCustomer方法作为AssociationMethodName,SalesOrder实体作为AssociationMethodEntityName。同样的,SalesOrders参数被指定为返回参数。最后,源实体(SourceEntity,就是驱动关系的实体)和目标实体(DestinationEntity)元素在其中也分别进行了定义。
关联方法可以在任何实体中存在(甚至是源实体和目标实体以外的实体)。唯一的一个要求是包含关联方法的实体必须写在其引用的其他实体的下面。比如本例中的SalesOrder实体必须放在Customer实体下面,因为在其中存在customer标识的引用。
< Associations >
< Association
AssociationMethodEntityName ="SalesOrder"
AssociationMethodName ="GetSalesOrdersForCustomer"
AssociationMethodReturnParameterName ="SalesOrders"
AssociationMethodReturnTypeDescriptorName ="SalesOrderDataReader"
Name ="CustomerToSalesOrders" >
< SourceEntity Name ="Customer" />
< DestinationEntity Name ="SalesOrder" />
</ Association >
</ Associations > - 增加LOBSystem根元素的版本号
MOSS会阻止我们上传一个版本号小于或等于当前所承载的版本的元数据文件。因此,如果我们使用前面章节中创建的元数据文件,这里必须要提高其版本号。
- 保存并上传修改完成的元数据文件到BDC共享服务
保存文件。打开管理中心,点左侧导航栏中的共享服务(通常名为SharedServices1)。在BDC一节中,点导入应用程序定义。点浏览,找到刚刚修改完成的元数据文件,双击。其他的应用程序定义项都用默认值就好,点导入。
- 使用业务数据WebPart来实现基于Customer的Orders筛选
1. 在我们的站点首页中添加一个“业务数据列表”WebPart和一个“与业务数据相关的列表”WebPart。
2. 在业务数据列表WebPart上,点“打开工具窗格”。
3. 在工具窗格中的类型输入框中,输入 Customer 并回车。SharePoint Server 2007会将输入的内容解析为Customer (CRMDB)实体。
4. 点确定后,customer实体就会显示在WebPart中了。
5. 在与业务数据相关的列表WebPart中,点“打开工具窗格”。
6. 在工具窗格中的类型输入框中,输入 SalesOrder并回车。注意到我们之前在关联中定义的CustomerToSalesOrders关系会自动出现在关系下拉列表中并选中。
7. 点应用。
8. 点SalesOrder列表WebPart的编辑菜单,点连接。点选获取相关项来源,然后选择Customer列表。
9. 这样,在Customer列表WebPart中点一个customer就可以查看相关的sales orders了。
你准备好进行第三方协助了吗?
关联没必要只停留在一层上。本节将描述如何添加一个LineItem实体,并与sales order相关联。
注:该实体非常简单。它没有实现任何方法。因此,它不会显示在搜索中也不存在一个业务数据操作,或用在关联性过滤中。它最主要的也是唯一的目的就是显示一个与SalesOrder有关系的实体。
- 创建一个ListItem实体
添加下面的XML内容到SalesOrder实体下面。正如之前提到的,这里实体间的顺序很重要。这个实体必须放在SalesOrder 实体下面,因为它的特定方法包含到SalesOrder 标识的引用。
< Entity Name ="LineItem" >
< Properties >
< Property Name ="Title" Type ="System.String" > Name </ Property >
</ Properties >
< Identifiers >
< Identifier Name ="LineItemID" TypeName ="System.Int32" />
</ Identifiers >
< Methods >
< Method Name ="GetLineItemsForSalesOrder" >
< Properties >
< Property Name ="RdbCommandText" Type ="System.String" >
SELECT
sod.SalesOrderDetailID,
p.Name,
p.ProductNumber,
sod.CarrierTrackingNumber,
sod.OrderQty,
sod.UnitPrice,
sod.LineTotal
FROM
Sales.SalesOrderDetail sod
INNER JOIN Production.Product p
on sod.ProductID = p.ProductID
WHERE
sod.SalesOrderID = @salesorderID
</ Property >
< Property Name ="RdbCommandType" Type ="System.String" > Text </ Property >
</ Properties >
< Parameters >
< Parameter Direction ="In" Name ="@salesorderID" >
< TypeDescriptor TypeName ="System.Int32" Name ="salesorderID"
IdentifierEntityName ="SalesOrder"
IdentifierName ="SalesOrderID" >
<!-- Note that we don't have any default values for this. -->
</ TypeDescriptor >
</ Parameter >
< Parameter Direction ="Return" Name ="LineItems" >
< TypeDescriptor TypeName ="System.Data.IDataReader, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
IsCollection ="true" Name ="LineItemDataReader" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Data.IDataRecord, System.Data,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
Name ="LineItemDataRecord" >
< TypeDescriptors >
< TypeDescriptor TypeName ="System.Int32"
IdentifierName ="LineItemID"
Name ="SalesOrderDetailID" />
< TypeDescriptor TypeName ="System.String"
Name ="Name" />
< TypeDescriptor TypeName ="System.Int32"
Name ="CarrierTrackingNumber" />
< TypeDescriptor TypeName ="System.Int16"
Name ="OrderQty" />
< TypeDescriptor TypeName ="System.String"
Name ="UnitPrice" />
< TypeDescriptor TypeName ="System.String"
Name ="LineTotal" />
</ TypeDescriptors >
</ TypeDescriptor >
</ TypeDescriptors >
</ TypeDescriptor >
</ Parameter >
</ Parameters >
<!-- Note that we have no finder or specific finder.
This is because we don't need the line item to show up
in anything other than a Related List Web Part. -->
</ Method >
</ Methods >
</ Entity >
- 添加Sales Order到List Item的关联
将SalesOrderToLineItems关联直接放在已有的关联下面。
< Association
Name ="SalesOrderToLineItems"
AssociationMethodEntityName ="LineItem"
AssociationMethodName ="GetLineItemsForSalesOrder"
AssociationMethodReturnParameterName ="LineItems"
AssociationMethodReturnTypeDescriptorName ="LineItemDataReader"
IsCached ="true" >
< SourceEntity Name ="SalesOrder" />
< DestinationEntity Name ="LineItem" />
</ Association >
- 上传元数据文件并添加一个与业务数据相关的列表WebPart
增加元数据文件的版本号并上传。最后,添加一个新的与业务数据相关的列表WebPart到我们的站点页面。这次,选择ListItem实体和GetLineItemsForSalesOrder关联。
小结:
BDC不仅可以显示LOB数据到门户中,还可以通过BDC关联来定义门户中的实体对LOB中其他实体内容的反应。业务数据关联允许我们使用业务数据列表WebPart来驱动与业务数据相关的列表WebPart ,从而实现主子行为。
其中需要我们掌握的要点有:
* 定义关联方法的实体必须放在所有与其有关的其他实体下面。
* 关联方法必须具备输入参数来映射所有源实体的标识。
* 关联方法的返回参数必须包含目标实体的标识。
查看视频