I got few questions around how to enumerate the properties for a global resource. So here is how you do it. Following sample spits the properties for all the global resources in the console window. This sample uses the manager version of the globalconfig object. The APIs in this object return the ADO RecordSets. SO we'll need to enumerate through the Fields collecitons.
GlobalConfig2FreeThreaded config = new GlobalConfig2FreeThreaded();
config.Initialize("");
Fields globalResources = config.Fields;
foreach (Field globalResource in globalResources)
{
_Recordset globalResourceProperties = globalResource.Value as _Recordset;
if (globalResourceProperties != null)
{
foreach (Field property in globalResourceProperties.Fields)
{
Console.WriteLine("{0} = {1}", property.Name, property.Value);
}
}
}
OrderSystem in CS2007 comprises of 2 site resources as it did in CS2002/2000. Orders migration is not an in place migration. Migration tool loads data from CS2002 tables, transforms it to CS2007 format and inserts it into CS2007 tables. Tool creates the CS2007 orders system schema in the same database as CS2002. Since all table names are unique it does not over write any out of the box CS2002/2000 tables (However if you’ve extended your CS2002/2000 database schema then it’s recommended to verify that there are no conflicting table names before running the migration tool, otherwise data from the tables with conflicting names will get deleted. For this you can open the Requisition.sql and TaxAndShipping.sql files installed with CS2007 installation under SDK/SiteCreate folder.). Following tables participate in migration process. Since OrderSystem migration is CPU intensive, it’s recommended to run the tool from a different machine than the Sql box so that SqlServer and the migration tool are not competing for the resources.
|
OrderSystem Site Resources |
CS2002/CS2000 |
CS2007 |
|
Transactions |
OrderGroups
OrderGroupAddresses
OrderFormHeader
LineItems |
PurchaseOrders
OrderAddresses
OrderForms
LineItems
|
|
TransactionConfig |
ShippingConfig
tableShippingRates
Region |
ShippingMethod
ShippingRates
RegionCodes |
Here I'm going to illustrate the data migration for the Runtime data present in the transaction database (i.e. Purchase Orders\Baskets\ Order Templates). Migration tool loads the CS2002 data in dictionary format using dbstorage. Data from the dictionary is converted to strongly typed objects using the Pipeline adapter. Once the objects are created they are persisted using the Save methods implemented by these objects. Pipeline adapter makes use of the mapping file specially customized for the migration purposes only (OrdersMigrationMappings.xml). Mapped storage system uses the default OrderObjectMappings file. Before the migration the tool verifies the data in CS2002 database and reports if data from a column will land in the blob column after the migration. You should carefully analyze these messages and if you don’t want data from a column to move into the blob column you’ll need to perform extensions to the order system. OrderMigrationMappings.xml file contains the mapping between the dictionary key and the properties in CS2007 object model and the orderobjectmappings.xml files contains the mapping for properties with the Sql table columns. These mapping are used to determine whether data from a strongly typed column in CS2002 database table will land in blob column in CS2007 table.
Since there can be large set of orders and baskets in your database, migration tool implements fault tolerant logic so that you’ll not need to restart the migration process if there are bad records in the database. If there are certain records which cannot be migrated successfully it keeps logging the OrderGroupId for such records in an ExceptionLog this log is different from the detailed error log used by the migration tool. After migration tool completes the migration you can go and fix such records and re-run the migration tool in the exception mode. In this case it will only migrate the records which are logged in the exception log. There is a threashold (10000 records) after which migration tool will error out and you’ll need to re-run it in the normal mode.
Migration for TransactionConfig data is straight forward. Data is loaded from the CS2002 tables and is inserted into CS2007 data tables. ShippingConfig table in CS2000 database did not contain the language column so the migration tool populates ‘Unknown’ value for this column in ShippingMethod table in CS2007 database. In CS2002 same shipping method in different languages was considered as different shipping method. This problem has been fixed in CS2007. But the migration tool cannot group the shipping methods from different languages so you’ll need to make use of the Customer and Order manager UI to group the same shipping methods in different language. CS2007 database schema has enforced few unique constraints in ShippingMethod and RegionCodes tables. These constraints were not present in the corresponding tables in CS2002/2000 database. Migration tool will report about the data which violates these constraints before migrating the data. If you see any such errors you’ll need to fix such rows manually and then run the migration tool.
Restrictions on Collection Semantics
The mapped storage, Pipeline Adapter, and XML serialization support in the Orders system will not work with custom collections that implement dictionary collection semantics. Any collection’s GetEnumerator method must return a list-type enumerator instead of an IDictionaryEnumerator.
PurchaseOrder and Deserialization Constructors
The only extendable Orders class that does not require a deserialization constructor is PurchaseOrder—it is the root class for storage through the mapped storage system and is not saved through serialization to the same table to which the Basket and OrderTemplate classes are saved. The different storage mechanisms serve different purposes. Baskets and OrderTemplates are saved and loaded often as a customer updates an order at a site; PurchaseOrders are created less often, when a user completes an order. Therefore Basket and OrderTemplate operations need higher performance, and give up some flexibility (for example, saving to multiple tables) that is present in the slower but full-featured storage mapping system used with PurchaseOrder.
Mapping Complex Container Relationships
The samples provided with the CS2007 do not cover mapping more complex container relationships among classes. The following are several rules that you must follow in order for relationships to work with the Orders storage mapping system:
The mapping system allows two classes (for example, A and B) to participate in either of the following relationships, but not both; attempting to create a mapping file that describes both relationships will result in unknown behavior.
A is contained by B through a collection class.
An inheritance model where A is the base class and B is the inherited class and one or both classes are mapped.
Multiple-parent container relationships are not allowed, creating such a relationship results in unpredictable behavior. For example, consider a case where there are classes A, B, and C. An invalid scenario results if B contains a collection of C, and A contains both a collection of B and a collection of C, such that C has two parent containing classes.
A collection relationship cannot be created mapping collections of the same type to different tables from the same class. An example of this is the base Orders class LineItem and its two collection members LineItem.OrderLevelDiscountsApplied and LineItem.ItemLevelDiscountsApplied, each of which contain a set of DiscountApplicationRecord instances. There is no way to map members of each of these collections to different tables; there is only one mapping allowed from the child class DiscountApplicationRecord to a set of tables, independent of parent collection instances to which they might belong.
Requiring Setters on Mapped Properties
In the CS2007, it is a requirement that any properties in extended Orders classes that are to be mapped to storage must have both a getter and a setter. The setter is required to restore data from the mapped storage system into a class instance.
During Basket and OrderTemplate persistence, the Orders system performs column matching against column names in the OrderTemplatesAndBaskets table. When a column of the table matches in a case-insensitive fashion the name of a strongly-typed or weakly-typed property of the Basket or OrderTemplate instance, the value of the property is placed in the column during save and the column value placed in the property during load. This allows you to perform queries against the column values; the binary data in OrderTemplatesAndBaskets.marshaled_data, which is the full binary serialization of the Basket or OrderTemplate instance, is not understandable by SQL Server.
When you wish to modify the OrderTemplatesAndBaskets table to add a column to participate in this matching, you must also modify following stored procedures that interact with this table:
SPI_OrderTemplatesAndBaskets SPS_Search_OrderTemplatesAndBasketsBySoldToIdOrderGroupId, SPS_Search_OrderTemplatesAndBasketsByOrderGroupId, SPS_Search_OrderTemplatesAndBasketsByStatusCodeSoldToId and SPS_Search_OrderTemplatesAndBasketsByStatusCodeSoldToIdName
These stored procedures do not need to be modified:
· SPD_OrderTemplatesAndBaskets
· SPD_BulkDeleteBaskets
· SPM_Ord_MetaData_OrderTemplatesAndBaskets
The following sections detail how to make changes to each of these stored procedures.
Modifying SPI_OrderTemplatesAndBaskets This stored procedure will either update (if the Basket or OrderTemplate row is pre-exisitng) or insert a row into OrderTemplatesAndBaskets. If you add a column to the OrderTemplatesAndBaskets table, perform the following steps to update SPI_OrderTemplatesAndBaskets:
· Add a parameter to SPI_OrderTemplatesAndBaskets that follows the pattern, “@@param_<ColumName>” in the same order that the new column is specified in the OrderTemplatesAndBaskets declaration. Note that the parameter @@param_marshaled_data must appear last in the parameter list.
· Modify the two UPDATE and one INSERT statements in the stored procedure to set the column value to the value of the parameter.
Modifying SPS_OrderTemplatesAndBasketsByStatusCodeSoldToIdName This stored procedure searches for a specific Basket or OrderTemplate based on the SoldToID and order name (name can be null). Update this stored procedure by adding the new column name to the two SELECT statements that perform the search query. Add the new column in the same order as its declaration in the OrderTemplatesAndBaskets table definition. Note that the marshaled_data column must be the first column in each of these SELECT statements.
Modifying SPS_OrderTemplatesAndBasketsByStatusCodeSoldToId
This stored procedure searches for a specific Basket or OrderTemplate based on the SoldToID. Update this stored procedure by adding the new column name to the SELECT statement that performs the search query. Add the new column in the same order as its declaration in the OrderTemplatesAndBaskets table definition. Note that the marshaled_data column must be the first column in each of these SELECT statements.
Modifying SPS_OrderTemplatesAndBasketsByOrderGroupId
This stored procedure searches for a specific Basket or OrderTemplate based on the OrderGroupId. Update this stored procedure by adding the new column name to the SELECT statement that performs the search query. Add the new column in the same order as its declaration in the OrderTemplatesAndBaskets table definition. Note that the marshaled_data column must be the first column in each of these SELECT statements.
Modifying SPS_OrderTemplatesAndBasketsBySoldToIdOrderGroupId
This stored procedure searches for a specific Basket or OrderTemplate based on the SoldToId and OrderGroupId. Update this stored procedure by adding the new column name to the SELECT statement that performs the search query. Add the new column in the same order as its declaration in the OrderTemplatesAndBaskets table definition. Note that the marshaled_data column must be the first column in each of these SELECT statements.
You can think of any class property as a name-value pair. Strongly typed properties are properties defined as part of a class definition. Weakly typed properties are properties that have not been added as class properties to a class, but instead are placed in a string indexer (this[string] in C#) as a name-value pair. This functionality is provided in all of the base Orders classes for backward compatibility with legacy COM-based pipeline components. Normally, weakly typed properties are serialized into a single binary large object (BLOB) as part of saving to storage. Weakly typed properties whose names start with an underscore, and those that are not serializable, are not serialized.
The Orders storage mapping system provides the ability to map individual weakly typed properties to their own columns, similar to the way in which you map strongly typed properties. The default Orders storage mapping file contains no weakly typed property mappings.
When saving a weakly typed property to storage, an exception is thrown by the storage code Microsoft.CommerceServer.Runtime.Orders.Basket.SaveAsOrder and Microsoft.CommerceServer.Runtime.Orders.PurchaseOrder.Save if the type of the weakly typed property is not compatible with the column's type.
The following example shows how to perform such a mapping from a weakly typed property UserNickname in the OrderAddress class to its own column added to the OrderAddresses table.
Step 1: Modify the Storage Mapping File
Only excerpts from the mapping file are shown in this step.
Adding the UserNickname Column
You must add a new column definition to the OrderAddresses table in which to store values from OrderAddress class instances.
Note
· The line numbers appear for clarity; remove them before using this code.
1 <Table Name="OrderAddresses">
2 <Columns>
3 <Column Name="OrderGroupId" DataType="uniqueidentifier" />
...
4 <Column Name="UserNickname" DataType="nvarchar" Precision="50" IsNullable="true" />
5 <Column Name="MarshalledData" DataType="image" IsNullable="true" />
6 </Columns>
7 </Table>
At line 4, add the new column definition for UserNickname as type nvarchar(50) and null-able. It is required that any column corresponding to a weakly typed property have a null-able column constraint. When the weakly typed property is not present in the name-value pair set, null is applied to the column value.
Adding a Weakly Typed Property to a Class Definition
Next, update the class definition for OrderAddress to add a definition for your new weakly typed property that you want to map. Only weakly typed properties mapped to their own columns must be added to the class definition; unmapped properties can simply be added to the name-value pairs on an ad hoc basis.
Note
· The line numbers appear for clarity; remove them before using this code.
1 <Class Name="OrderAddress">
2 <Property Name="OrderAddressId" />
...
3 <WeaklyTypedProperty Name="UserNickname" />
4 </Class>
At line 3, add a special type of XML node to the class, WeaklyTypedMember. The only attribute for this node is the Name attribute, which defines the name of the weakly typed property.
Adding the Mapping for the Weakly Typed Property
Finally, change the OrderAddress mapping to add a mapping between the weakly typed property and the column.
Note
· The line numbers appear for clarity; remove them before using this code.
1 <ClassTableMap Class="OrderAddress" Table="OrderAddresses">
2 <PropertyMap Property="OrderAddressId" Column="OrderAddressId" />
...
3 <PropertyMap Property="UserNickname" Column="UserNickname" />
4 </ClassTableMap>
At line 3, add a PropertyMap XML node containing the source object property and the target database column names.
Step 2: Use OrderMapping.exe on the Mapping File
See the notes from the MyLineItem sample on how to use OrderMapping.exe with a Web.config file. You use the generated OrdersStorage.sql file to update the site database. This new file contains changes to the default Orders stored procedures to support saving to and loading from the new table.
Step 3: Modify the Site Database
In the Commerce Server 2007, you perform modifications to existing tables. Assuming this sample is applied to the CSharpSite sample provided with the CS2007, this means adding a column named UserNickname of type nvarchar(50) to the OrderGroupAddresses table. After adding the column, you update the stored procedures in the database. Load the OrdersStorage.sql file into the SQL Server Query Analyzer and run it against the site database (CSharpSite_transactions in the CSharpSite demonstration site provided with the CS2007).
Step 4: Deploy the Mapping File
The MyLineItem sample describes the steps to deploy the new version of the mapping file.
The Orders system Commerce Server 2007, enables you to extend the default objects with custom strongly typed properties and custom methods. The Orders system is accessible through the Microsoft.CommerceServer.Runtime.Orders namespace.
Using the Orders system, you can add custom properties to existing classes and collections of objects to model your specific business needs, which you can then map to your database and, through the Order System Pipeline Adapter, to Dictionary keys for use with COM-based pipeline components.
Order capture system classes are persisted to SQL storage in two ways:
· Serialization with column matching—used when high performance is a requirement, because OrderTemplate and Basket are loaded and saved often and serialization is faster. This persistence mechanism is different from the mapped storage system used by purchase orders. The order is serialized using binary serialization and placed in the OrderTemplatesAndBaskets.marshaled_data column. Additionally, during load and save, when a column of the OrderTemplatesAndBaskets table matches (in a case-sensitive fashion) the name of a strongly-typed or weakly-typed property of the Basket or OrderTemplate instance, the value of the property will be copied to the column on save and copied into the new instance from the column during load. This allows you to perform queries against the column values, since the binary data in the marshaled_data column is not readable or queryable by SQL Server. See the
· Mapped Storage System—purchase orders use the mapped storage subsystem, which provides more flexibility than serialization, but at the cost of some performance. It provides the ability to map individual class properties to one or more SQL table columns. This enables the user to perform data mining on placed orders.
The Pipeline Adapter translates an OrderForm class graph into one or more legacy OrderForm-style COM IDictionary instances, which are then passed as the “order” IDictionary to COM-based pipeline components during execution of a pipeline. A Pipeline Adapter mapping XML file provides the ability to specify how existing and new class members you may add will be mapped to IDictionary keys during Pipeline Adapter translation.
The following sections describe extending the Orders system using Microsoft® Visual Studio® .NET and the C# managed-code language. The Orders system supports any Common Language Runtime (CLR) based language. The following table lists the base classes for the Orders system and indicates whether each class is extensible and notes derived classes.
|
Class Name |
Extensibility |
|
OrderContext |
Non-extensible and sealed. |
|
OrderGroup |
Non-extensible. |
|
Basket |
Extensible and derived from OrderGroup. |
|
PurchaseOrder |
Extensible and derived from OrderGroup. |
|
OrderTemplate |
Extensible and derived from OrderGroup. |
|
OrderGroupCollection |
Non-extensible and sealed. |
|
OrderForm |
Extensible. |
|
PromoCodeStringCollection |
Non-extensible and sealed. |
|
OrderFormCollection |
Non-extensible and sealed. |
|
LineItem |
Extensible. |
|
LineItemCollection |
Non-extensible and sealed. |
|
DiscountApplicationRecordBase |
Non-extensible |
|
DiscountApplicationRecord |
Extensible and derived from DiscountApplicationRecordbase |
|
DiscountApplicationRecordCollection |
Non-extensible and sealed. |
|
ShippingDiscountCollection |
Non-extensible and sealed. |
|
ShippingDiscountRecord |
Extensible and derived from DiscountApplicationRecordbase |
|
OrderAddress |
Extensible. |
|
OrderAddressCollection |
Non-extensible and sealed. |
|
Shipment |
Extensible. |
|
ShipmentCollection |
Non-extensible and sealed. |
|
PromoCodeRecord |
Extensible. |
|
PromoCodeRecordCollection |
Non-extensible and sealed. |
|
Payment |
Extensible. |
|
CreditCardPayment |
Extensible and derived from Payment. |
|
GiftCertificatePayment |
Extensible and derived from Payment. |
|
PurchaseOrderPayment |
Extensible and derived from Payment. |
|
CashCardPayment |
Extensible and derived from Payment. |
|
PaymentCollection |
Non-extensible and sealed. |
Virtual Methods
The following are the virtual methods of the Orders base classes that you can override in your derived classes to provide custom behavior. The methods are grouped by class.
OrderGroup, Basket, OrderTemplate, PurchaseOrder
public virtual void GetObjectData(SerializationInfo, StreamingContext)
public virtual void Save()
public virtual void Clear()
public virtual IEnumerator GetEnumerator()
public virtual void RunPipeline(PipelineInfo)
OrderForm
public virtual void GetObjectData(SerializationInfo, StreamingContext)
OrderAddress
public virtual void GetObjectData(SerializationInfo, StreamingContext)
LineItem
public virtual void GetObjectData(SerializationInfo, StreamingContext)
DiscountApplicationRecord, ShippingDiscountRecord
public virtual void GetObjectData(SerializationInfo, StreamingContext)
Payment, CreditCardPayment, GiftCertficatePayment, PurchaseOrderPayment, CashCardPayment
Public virtual void GetObjectData(SerializationInfo, StreamingContext)
PromoCodeRecord
Public virtual void GetObjectData(SerializationInfo, StreamingContext)
Shipment
Public virtual void GetObjectData(SerializationInfo, StreamingContext)
Type Conversions in the Mapped Storage System
The mapped storage system used in PurchaseOrder storage only allows certain property types to be mapped. Mapping complex types (e.g. properties that return references to classes) is not allowed.
The following table illustrates the allowed type conversions between .NET-based data types and SQL data types. The far left column lists the SQL data types and the top row lists the .NET-based data types. Allowed conversions are marked with an X.
|
|
Int64 |
Boolean |
DateTime |
Decimal |
Double |
Int32 |
String |
Single |
GUID |
|
Bigint |
X |
|
|
|
|
|
|
|
|
|
Bit |
|
X |
|
|
|
|
|
|
|
|
Datetime |
|
|
X |
|
|
|
|
|
|
|
Float |
|
|
|
|
X |
|
|
|
|
|
Int |
|
|
|
|
|
< |