Welcome to MSDN Blogs Sign in | Join | Help

Syndication

Tags

    No tags have been created or used yet.
Extending the Orders System

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

 

 

 

 

 

X

 

 

 

Money

 

 

 

X

 

 

 

 

 

NText

 

 

 

 

 

 

X

 

 

Numeric

 

 

 

X

 

 

 

 

 

NVarchar

 

 

 

 

 

 

X

 

 

NChar

 

 

 

 

 

 

X

 

 

Real

 

 

 

 

 

 

 

X

 

Uniqueidentifier

 

 

 

 

 

 

 

 

X

 

 Note

·         The following SQL data types are not allowed for mapped storage:

·         Binary

·         Char

·         Decimal

·         Image

·         Smalldatetime

·         Smallint

·         Smallmoney

·         SQLVariant

·         Sysname

·         Text

·         Tinyint

·         Varbinary

·         Varchar

Strongly-typed and weakly-typed properties

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-keyed indexer (this[string] in C#) as a name-value pair. This functionality is provided in many (but not 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.

For instance, setting a weakly typed property _currency in an instance of OrderForm would look like the code below. The “_currency” weakly-typed property, because it starts with an underscore, would not be serialized as part of saving the weakly-typed properties for storage to a SQL table.

OrderForm orderForm = new OrderForm();

orderForm["_currency"] = "USD";

 

Weakly typed properties are mapped directly to Microsoft.CommerceServer.Runtime.Dictionary entries during Pipeline Adapter marshaling to and from the Commerce Server 2002 legacy COM-based orders pipeline.

Serialization code will throw UnSupportedTypeException if a non-serializable property is found in the idexer.

 

  Note

·         You cannot use weakly typed properties with the same name as strongly typed properties or having the same name as a key in the Pipeline Adapter mapping file that maps to a strongly-typed property.

All Orders system classes support weakly typed property indexers.

 

Orders Extensibility Checklist

The following provides an overview of the steps necessary to extend the Orders system:

1.      Derive new classes when extending base orders classes, or create new classes and build an assembly containing the finished code. Take into account versioning issues and guidelines when creating extended classes.

2.      Update the Orders storage mapping file with the changes. By default, the name of this mapping file is OrderObjectMappings.xml.

3.      Update the Orders pipeline mapping file with the changes. By default, the name of this mapping file is OrderPipelineMappings.xml.

4.      Update the Web.config file with the changes.

5.      Use the OrderMapping.exe tool with the Orders storage-mapping file to generate Orders stored procedure code.

6.      Update the site database with table changes needed to support new classes and apply the new stored procedures.

7.      If you are modifying the OrderTemplatesAndBaskets table to add columns for property matching, you must update the SPI_OrderTemplatesAndBaskets, SPS_Search_OrderTemplatesAndBasketsBySoldToIdOrderGroupId, SPS_Search_OrderTemplatesAndBasketsByOrderGroupId, SPS_Search_OrderTemplatesAndBasketsByStatusCodeSoldToId and SPS_Search_OrderTemplatesAndBasketsByStatusCodeSoldToIdName stored procedures to add the new column names.

8.      Deploy the new assembly and mapping files.

9.      Don’t forget to upgrade the OrdersWebService. If you’re using the Customer and order manager UI.

Getting Started

In this section we’re going to cover extending Commerce Server Order System class and also how to add completely new class. For the first one I’m going to demonstrate how to extend LineItem class with a new property called WidgetDescriptionProperty. And for the second one I’m going to add a new entity called VirtualGiftCertificate which has a 1:m relationship with OrderForm class. For this we’re going to implement VirtualGiftCertificateCollection class. A new property of VirtualGiftCertificateCollection type will be added to the OrderForm class which requires extending the OrderForm class also. This collection can contain one or more instances of VirtualGiftCertificate. Code for these samples can be found in Commerce Server 2007 Install folder under Sdk\Samples\OrdersExtensibility.

 

Before you begin extending the Orders system, you must first create a new solution.

To create a new solution

1.      In the Visual Studio.NET window, click File, click New, and then click Project.

In the New Project window, choose the Visual C# Class Library Project. This creates a new managed code assembly as shown in the following figure.

2.      In the New Project dialog box, in the Name field, type the name of the project, for example: MyOrders and click OK.

After you create the project, you must add a reference to the Commerce Server Base Class Library (BCL).

3.      In the Microsoft Visual Studio .NET window, click Project, and then click Add Reference.

In the Select Component window, click the Microsoft.CommerceServer.Runtime.dll assembly.

4.      You can browse for the Microsoft.CommerceServer.Runtime.dll assembly under the “Microsoft Commerce Server 2007\Assemblies” folder on the installation drive.

5.      In the Add New Item – MyOrders window, right-click the MyOrders project, and then click Add New Item.

In the Add New Item – MyOrders dialog box, click Class to add a new C # class, and name it MyLineItem using the Name field as shown in the following figure. This creates a new file in the project called MyLineItem.cs.

 

Extending the LineItem Base Class

The following information and source code demonstrates how to extend the LineItem object by a single property and store it in the same table as the other properties. By default, the LineItem object is stored in the LineItems table.

Step 1: Derive a New LineItem Class

Derive a new LineItem class and add a new strongly typed property as shown in the following code.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1  namespace MyOrdersClasses

2  {

3  [Serializable]

4  public class MyLineItem : LineItem

5  {

6    private string widgetDescriptionProperty;

7    public MyLineItem() : base()

8    {

9      this.widgetDescriptionProperty = "No Description";

10   }

11   public string WidgetDescriptionProperty

12   {

13     set

14     {

15       if (value != null)

16         value = value.Trim();

17       SetDirty(value);

18       this.widgetDescriptionProperty = value;

19     }

20     get

21     {

22       return this.widgetDescriptionProperty;

23     }

24   }

25   protected MyLineItem(SerializationInfo info, StreamingContext context) : base(info, context)

26   {

27     try

28     {

29       widgetDescriptionProperty = info.GetString("widgetDescriptionProperty");

30     }

31     catch(SerializationException se)

32     {

33       // Handle different versions here

34     }

35   }

36   [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]

37   public override void GetObjectData(Serialization info, StreamingContext      context)

38   {

39     base.GetObjectData(info, context);

40     info.AddValue("widgetDescriptionProperty", widgetDescriptionProperty);

41   }

42 }

43

44 }  // End namespace MyOrdersClasses

 

Line 1: Define your own namespace for derived classes. Configuration information you change will include this namespace name.

Line 3: Your extended class must be marked with the Serializable attribute to support serialization.

Line 5: LineItem is a public, extensible class. You create a custom implementation of this class called MyLineItem.

Line 6: You back up the public property WidgetDescriptionProperty with a private string field named widgetDescriptionProperty.

Lines 7-10: Each class must implement a default constructor. This must in turn call the constructor for the base object.

Line 9: Each custom property exposed must have an appropriate default value set during construction of the object.

Line 11: You create a strongly typed, public property called WidgetDescriptionProperty, which is a read/write property.

Lines 13-19: The set method for this strongly typed property can perform any custom validation on the value for the property. It trims any spaces from the beginning and end of the value, and calls the public method of SetDirty with the value of what is being set. The SetDirty method performs automatic maximum length validation of string values against their respective column widths in underlying storage, and allows for optimizations within the Orders system and updates the appropriate DateTime stamps.

Lines 20-23: The get method for this strongly typed property can perform any custom actions necessary.

Line 25: Each class must implement ISerializable. As a part of the ISerializable interface, you must implement a constructor that takes streaming information. The constructor must call the base() implementation. The base implementation is responsible for setting the values of all the base class properties.

Lines 25-35: The deserialization constructor allows for setting the values of the object. The derived constructor for the class is responsible for setting the values of its own properties—in this case, the field that backs the WidgetDescriptionProperty.

Lines 31-34: In case the code is deserializing a previous version of the object, when setting the values, it should handle the case when the property does not exist in the serialized stream.

Lines 36-41: When serializing the object, call the ISerializable method ISerializable.GetObjectData. This method calls the base implementation first. The implementation of ISerializable.GetObjectData is responsible for serializing all of the properties that should be stored from an object. The security demand attribute on GetObjectData is the minimum recommended security demand.

This example contains several important points of which you should be aware. They are as follows:

·         An explicit field named widgetDescriptionProperty backs the strongly typed property, as opposed to the value coming from a method or another object. You can calculate the value of the field at the time you access the get method.

·         There are no Indexer properties defined.

All strongly typed properties are writeable (for example, implemented as get and set methods).

Step 2: Modify the Orders Storage Mapping File

You have created a new assembly containing a class derived from LineItem. Next, you must revise the Orders system storage-mapping file to account for the changes you made. The default version of the mapping file is stored in the virtual root of the CSharpSite sample site included with the Commerce Server 2007, in the OrdersObjectMappings.xml file. Rename this file to indicate that it is a custom version. Additionally, update the linkage in the Web.config file (the <MappingFiles> XML tag StorageMappingFilename attribute) so the site points to the new file name. For the purposes of this sample, modify the existing file. The following descriptions show excerpts from the file and indicate recommended changes

 

Modifying the SQL Table Definition

The following is a portion of the table definition for the LineItems table.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Table Name="LineItems">

2  <Columns>

...

3   <Column Name="WidgetDescriptionProperty" DataType="nvarchar" Precision="64" IsNullable="true" />

4   <Column Name="MarshalledData" DataType="image" IsNullable="true" />

5  </Columns>

 

Add a new column (line 3) providing storage for your new property, which requires use of the nvarchar SQL data type (as opposed to varchar).Choose a maximum length in the Precision attribute that is appropriate for the maximum string length you expect for this property. The IsNullable attribute corresponds to the null column constraint in the SQL language. Since you allow null values for the property in the class code, you must make this column null-able.

Note that in this sample you do not rename the table; however, you do change class information to point to the new class name. When you regenerate the Orders system stored procedure code later, you will be responsible for generating your own SQL script (or using the SQL Server user interface) to physically add the new column to the existing LineItems table. You must add the column with the same attributes as above; in other words, it must be named the same, be of type nvarchar(64), and have a null column constraint.

 

Modifying the Class Definition

Next, you make changes to the class name and members in the mapping file to point to MyLineItem instead of LineItem. The following is a modified section of the file containing the class definition for LineItem.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Class Name="MyLineItem">

2  <Property Name="LineItemID" />

...

3  <Property Name="OrderLevelDiscountsApplied" />

4  <Property Name="ItemLevelDiscountsApplied" />

5  <Property Name="WidgetDescriptionProperty" />

6 </Class>

 

On line 1, change the class name from LineItem to MyLineItem. On line 5, add a member definition for the new property WidgetDescriptionProperty.

 

Modifying Collection Relationships

Next, you must modify the parent-child collection relationships for the classes.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1  <CollectionRelationships>

...

2   <CollectionRelationship Name="LineItems" ParentClass="OrderForm" ParentProperty="LineItems" ChildClass="MyLineItem" />

3   <CollectionRelationship Name="LineItemDiscountsApplied" ParentClass="MyLineItem" ParentProperty="OrderLevelDiscountsApplied" ChildClass="DiscountApplicationRecord" />

4   <CollectionRelationship Name="LineItemDiscountsApplied" ParentClass="MyLineItem" ParentProperty="ItemLevelDiscountsApplied" ChildClass="DiscountApplicationRecord" />

...

5  </CollectionRelationships>

 

Above is a modified version of the CollectionRelationships section of the mapping file. Change the child relationship from LineItem to OrderForm.LineItems to point instead to MyLineItem (line 2), and the parent relationships from LineItem.OrderLevelDiscountsApplied and LineItem.ItemLevelDiscountsApplied to the DiscountApplicationRecord class (lines 3, 4) to point to MyLineItem.

 

Modifying Class-Table Mappings

Next, you modify the mapping from the LineItem class to the LineItems table. The following is a modified excerpt from the <Mappings> section of the file:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <ClassTableMap Class="MyLineItem" Table="LineItems">

2  <PropertyMap Property="OrderGroupID" Column="OrderGroupID" />

...

3  <PropertyMap Property="ModifiedBy" Column="ModifiedBy" />

4  <PropertyMap Property="WidgetDescriptionProperty" Column="WidgetDescriptionProperty" />

5 </ClassTableMap>

 

Change the class name in the mapping to MyLineItem, and add a new field mapping between MyLineItem.WidgetDescriptionProperty and LineItems.WidgetDescriptionProperty. This new copy of the file should replace the old version in the virtual root of the site.

Step 3: Modify the Orders Pipeline Mapping File

Changes to the Orders classes also require changing pipeline mapping information defined in the OrderPipelineMappings.xml file. You use this file to describe how instances of classes used with the Orders system are marshaled to and from legacy Commerce Server IDictionary instances for use with the legacy order pipeline. The changes required are similar in spirit though not in format, to the changes made to the object-mapping file. First, you change the parent-child collection relationship from OrderForm.LineItems to the LineItem class. The following excerpt from the OrderPipelineMappings.xml file was modified to point to the MyLineItem class:

<Class Name="OrderForm">

 <Property Name="OrderFormID" DictionaryKey="orderform_id"/>

...

 <Collection Name="LineItems" DictionaryKey="items" KeyType="SimpleList" referTo="MyLineItem"/>

...

</Class>

 

The Collection tag describes a parent-child collection relationship. The name attribute describes the property name of the collection within the parent. The dictionaryKey attribute indicates the name of the key within the IDictionary to which the collection should map. The keyType attribute indicates the type of legacy Commerce Server collection that you should used to hold the contents of the collection; in this case, you are mapping to an ISimpleList. The referTo attribute indicates the class type contained within the collection. You change the referTo value to MyLineItem since you are switching to MyLineItem instances. The pipeline-mapping file also contains class definitions used for mapping information. The following is a relevant portion of the LineItem class definition, modified to show your new class name and to add your new property. The name to which the property is mapped can be anything that does not conflict with another property's name. The convention is to use the older, non-Pascal naming convention when translating into a pipeline context, so you use the name widget_description_property:

<Class Name="MyLineItem">

...

<Property Name="WidgetDescriptionProperty" DictionaryKey="widget_description_property"/>

 <Collection Name="ItemLevelDiscountsApplied" DictionaryKey="_itemlevel_discounts_applied" KeyType="SimpleList" ReferTo="DiscountApplicationRecord"/>

 <Collection Name="OrderLevelDiscountsApplied" DictionaryKey="_orderlevel_discounts_applied" KeyType="SimpleList" ReferTo="DiscountApplicationRecord"/>

</Class>

Step 4: Modify the Web.config File

You must modify the Web.config file Orders information to change the definition of a LineItem to MyLineItem. The Web.config file contains an <Orders> section that contains a <Types> subsection. The <Types> subsection contains individual type definitions that relate an Orders class to its current derived class name and provides information about the assembly to use to find the class. The following is the relevant <Types> subsection with the modifications you will need for this sample:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Types>

2  <Type Key="Basket" UserTypeName="Basket" AssemblyType="GAC" NameSpace="Microsoft.CommerceServer.Runtime.Orders" Assembly="Microsoft.CommerceServer.Runtime, Version=5.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

...

3  <Type Key="LineItem" UserTypeName="MyLineItem" AssemblyType="Local" NameSpace="MyOrdersClasses" Assembly="MyOrders" />

...

4 </Types>

 

Line 2 shows a typical type definition for an original Orders type. 

The changes you made on line 3 include the following:

·         UserTypeName: You change this to MyLineItem to match your new class. The Key attribute remains unchanged since its value indicates the original Orders class from which you are deriving.

·         AssemblyType: You are using the Local value, which implies that you are going to deploy the assembly locally in the virtual root of the Web application.

·         NameSpace: Change to the MyOrdersClasses namespace.

Assembly: Change to a local assembly deployment.

 

Step 5: Use OrderMapping.exe on the Storage File

OrderMapping.exe is a tool provided with Commerce Server 2007. It provides pre-deployment validation of a storage-mapping file against a Web.config file and the assemblies specified in it. It also uses the information gathered to generate Orders stored procedures used for loading and saving mapped classes.

Because this sample uses local deployment of the assembly, you must run OrderMapping.exe from a directory containing the assembly. The command line syntax to use is as follows:

OrderMapping.exe /w <web.config path>

 

For instance, if you copy the MyOrders.dll assembly into the virtual root directory of the Web application, along with your new mapping files and the modified Web.config file, you could execute this command from that directory as follows:

OrderMapping.exe /w web.config

 

OrderMapping.exe opens the Web.config file, reads the type definitions in the Orders section, loads the assemblies, and performs a large number of validations between the contents of the mapping file and the assemblies. The OrderMapping.exe prints warnings, errors, and informational messages to the console. These same checks are performed at load time of a Web application that uses Orders, but in this case, if an error is found in the mapping an exception is thrown, aborting load of the application. The output of this command is a new SQL data definition language file named OrdersStorage.sql.

 

Step 6: Modify the Existing Database

In the Commerce Server 2007, you must perform modifications to existing tables. Assuming you apply this sample to the CSharpSite sample provided with the CS2007, this means you must modify the CSharpSite_transactions database, and add a new column named WidgetDescriptionProperty of type nvarchar(64) to the LineItems table.

After updating the table definitions, you must 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 7: Deploy the New Assembly and Mapping Files

There are several more steps to completing the changes needed to use MyLineItem from ASP.NET-based code. Note that these steps provide a simple deployment scheme using one computer. For a more advanced deployment, you can use the Commerce Server Site packager (Pup).

As with any .NET-based assembly code, there are two ways to deploy—locally and through the Global Assembly Cache (GAC). Local deployment implies that you copy the assembly DLL to the virtual root of the Web server. GAC deployment implies that the assembly is strongly named (signed with a public-private key pair) and that you use the gacutil.exe to provide a link to the assembly through the global assembly cache. Either method is usable as long as the web.config type definition contains a valid assembly locator string to find the assembly.

  Note

·         If you did not copy the changes you made to the XML files to the virtual root, then you should copy them there now.

Changing the Web.config file causes a reload of settings (including re-reading of the OrderObjectMappings.xml file). Reset Microsoft Internet Information Services (IIS) to ensure that the settings and XML files are re-read.

 

Implementing Virtual Gift Certificates

The following topics explain how to add a new collection to the existing OrderForm class.

Step 1: Create the New Class

In Visual Studio .NET you create a new class to hold information about the Virtual Gift Certificates. Then, you create a collection that models a one-to-many relationship between an OrderForm and a VirtualGiftCertificate as shown in the following code. Note that this code is abbreviated.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1   namespace MyOrdersClasses

2   {

3   [Serializable]

4   public class VirtualGiftCertificate : MappedStorageBase, ISerializable

5   {

6     private const int currentClassRevision = 1;

7     private int virtualGiftCertificateID;

8     private int giftCertificateNumber;

9     private int giftCertificatePin;

10    private Decimal price;

11    private Decimal balanceAmount;

12    private Guid orderGroupID;

13    private Guid orderFormID;

14    private OrderForm parentOrderForm;

15    public VirtualGiftCertificate() : base()

16    {

17      virtualGiftCertificateID = -1;

18      orderGroupID = Guid.Empty;

19      orderFormID = Guid.Empty;

20    }

21    protected VirtualGiftCertificate(SerializationInfo info, StreamingContext context)

22    {

23      this.orderFormID = (Guid)info.GetValue("OrderFormID", typeof(Guid));

24      this.orderGroupID = (Guid)info.GetValue("OrderGroupID", typeof(Guid));

25      this.virtualGiftCertificateID = (int)info.GetValue("VirtualGiftCertificateID", typeof(int));

26      this.giftCertificateNumber = (int)info.GetValue("GiftCertificateNumber", typeof(int));

27      this.giftCertificatePin = (int)info.GetValue("GiftCertificatePin", typeof(int));

28      this.price = (Decimal)info.GetValue("Price", typeof(Decimal));

29      this.balanceAmount = (Decimal)info.GetValue("BalanceAmount", typeof(Decimal));

30      this.parentOrderForm = (OrderForm)info.GetValue(“ParentOrderForm”, typeof(OrderForm));

31    }

32    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]

33    public void GetObjectData(SerializationInfo info, StreamingContext context)

34    {

35      info.AddValue(“Ver”, currentClassRevision);

36      info.AddValue("OrderFormID", this.orderFormID);

37      info.AddValue(“ParentOrderForm”, this.parentOrderForm);

38      ...

39    }

40    public int VirtualGiftCertificateID

41    {

42      set

43      {

44        SetDirty(value);

45        virtualGiftCertificateID = value;

46      }

47      get

48      {

49        return virtualGiftCertificateID;

50      }

51    }

52    ...

53    public Guid OrderGroupID

54    {

55      set

56      {

57        SetDirty(value);

58        orderGroupID = value;

59      }

60      get

61      {

62        return orderGroupID;

63      }

64    }

65    public Guid OrderFormID

66    {

67      set

68      {

69        SetDirty(value);

70        orderFormID = value;

71      }

72      get

73      {

74        return orderFormID;

75      }

76    }

77    public void override SetDirty(object propertyValue)

78    {

79      // Check to see if StorageLoadInProgress is set - if so, skip

80      // processing of this call.

81      if (!StorageLoadInProgress)

82      {

83        // Call the base method first to allow automated value checking

84        // to throw an exception if applicable.

85        base.SetDirty(propertyValue);

86

87        // No local last modified time to update, so simply call

88        // the parent.

89        if (this.parentOrderForm != null)

90          this.parentOrderForm.SetChildDirty();

91      }

92    }

93    public void override SetChildDirty()

94    {

95      // Pass the call on to the parent if not loading.

96      if (!StorageLoadInProgress && this.parentOrderForm != null)

97        this.parentOrderForm.SetChildDirty();

98    }

99    public void override SetChildDirty(DateTime modificationTime)

100   {

101     // Pass the call on to the parent if not loading.

102     if (!StorageLoadInProgress && this.parentOrderForm != null)

103       this.parentOrderForm.SetChildDirty(modificationTime);

104   }

105   public override void SetParent(Object parentObject)

106   {

107     if (parentObject == null)

108     {

109       this.parentOrderForm = null;

110       this.orderGroupID = Guid.Empty;

111       this.orderFormID = Guid.Empty;

112     }

113     else

114     {

115       this.parentOrderForm = (OrderForm)parentObject;

116       this.orderFormID = this.parentOrderForm.OrderFormID;

117       if (this.ParentOrderForm.ParentOrderGroup != null)

118         this.orderGroupID = this.parentOrderForm.ParentOrderGroup.OrderGroupID;

119     }

120   }

121 }

122 }  // End namespace MyOrdersClasses

 

Line 1: Define your own namespace for derived classes and configuration. Information you change in this sample will include this namespace name.

Line 3: The class must support the Serializable attribute.

Line 4: The name of the class is VirtualGiftCertificate. This is a non-collection class and therefore must derive from and implement the abstract portions of the Microsoft.CommerceServer.Runtime.MappedStorageBase abstract base class. It may also implement ISerializable if you wish to use the default serializer; the sample implements the interface in order to support serialization versioning.

Line 6: This private integer indicates the current revision level of this class, and is used for versioning support.

Lines 7-11: These are custom fields specific to this object. If a field should not be stored during Basket and OrderTemplate serialization, it should be marked with the NonSerialized attribute (this is not demonstrated in this sample).

Lines 12-13: You must have a field backing the OrderGroupID property, which is a copy of the grandparent OrderGroup.OrderGroupID property. You also must have a backing field for the key of the direct parent (OrderFormID).

Line 14: In addition, this object holds a reference to the parent object instance that contains this object, in this case an OrderForm. You will need this later so you can notify the parent of changes (for time stamp updates and query optimization).

Lines 15-20: The storage code requires a default constructor. As long as a default constructor exists, you can use other constructors. It should call the base constructor (the default constructor for MappedStorageBase). The constructor should initialize all of the custom fields.

Lines 21-31: A deserialization constructor is required for ISerializable support. See the full implementation in the sample code file for a complete example of how to implement this. The only extendable Orders class that does not need to implement a deserialization constructor is PurchaseOrder, which is the root class for storage through the mapped storage system and is not saved through serialization to the same table the Basket and OrderTemplate classes are saved to.

Lines 32-39: GetObjectData is required for ISerializable support. The security demand attribute shown is the minimum recommended security demand for GetObjectData implementations. Note the addition of the currentClassRevision name-value pair to the serialization data; this revision may be used in a later class revision to handle backward compatibility for persisted, serialized data. The full implementation of this method is available in the sample code.

Lines 40-51: This is an example of a strongly typed property. It must implement both a getter and setter in order to be compatible with the Orders storage system in Commerce Server 2007. SetDirty is called to cause change notifications to propagate to the parent.

Lines 53-76: Implement strongly typed properties for the parent order form ID and grandparent order group ID like any other property, including calls to SetDirty.

Lines 77-92: MappedStorageBase.SetDirty implementation. This method is called by class property set accessor and internal class logic when class instance contents change, to update local and parent change information. The propertyValue parameter is the value provided to the property set accessor. This method serves several purposes, as listed:

·         It allows the local class to update its own "last modified" DateTime property (if present) in a common fashion.

·         When implemented according to guidelines in the documentation for MappedStorageBase.SetDirty, it ensures that modification date updates propagate to parent classes by calling SetChildDirty on the parent.

·         It allows the Orders system to support optimistic concurrency in the site database.

·         It allows the storage implementation to optimize SQL update queries to minimize thrashing and the amount of data marshaled and sent across the network.

·         When used with the StorageLoadInProgress Boolean value in the MappedStorageBase base class, it ensures that LastModified times are not updated while loading from storage.

·         When base.SetDirty(object) is called, automatic string property length validation is performed against column widths specified in the storage mapping file. See the documentation on MappedStorageBase.SetDirty for more information.

Lines 93-104: MappedStorageBase.SetChildDirty method implementations. You implement these despite that this class is not currently a parent in a collection relationship (for example, it does not contain any collections that are mapped). These methods are called by child instances from their SetDirty implementations, just as you call these methods on OrderForm from your SetDirty implementation. These calls would update a local last modified timestamp if you had one, and then pass the call upward to the parent.

Lines 105-120: MappedStorageBase.SetParent method implementation. This is called during OrderGroup conversion (for example, from a Basket to a PurchaseOrder), when adding the object or a parent to a collection, or when removing the object from a collection, to propagate the parent change throughout the class hierarchy. The object reference parameter is a reference to the direct parent (OrderForm in this case). You cast it to the correct type, and then use the reference to fill in your order form ID copy, the order group ID copy, and the parent order form reference.

 

Step 2: Create a New Collection Class

 

Next, you create a new collection class to hold a set of virtual gift certificates. The following code is an excerpt from the full sample.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1  namespace MyOrdersClasses

2  {

3  [Serializable]

4  public class VirtualGiftCertificateCollection : ICollection, ISerializable

5  {

6    private ArrayList virtualGiftCertificates;

7    internal OrderForm parentOrderForm;

8    public VirtualGiftCertificateCollection(OrderForm parentOrderForm)

9    {

10     this.virtualGiftCertificates = new ArrayList();

11     this.parentOrderForm = parentOrderForm;

12   }

13   public VirtualGiftCertificateCollection(SerializationInfo info, StreamingContext context)

14   {

15     this.virtualGiftCertificates = (ArrayList)info.GetValue("VirtualGiftCertificates", typeof(ArrayList));

16     this.parentOrderForm = (OrderForm)info.GetValue(“ParentOrderForm”, typeof(OrderForm));

17   }

18   [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]

19   public void GetObjectData(SerializationInfo info, StreamingContext context)

20   {

21     info.AddValue("VirtualGiftCertificates", this.virtualGiftCertificates);

22     info.AddValue(“ParentOrderForm”, this.parentOrderForm);

23   }

24   public int Count

25   {

26     get

27     {

28       return this.virtualGiftCertificates.Count;

29     }

30   }

31   ...

32   public IEnumerator GetEnumerator()

33   {

34     return virtualGiftCertificates.GetEnumerator();

35   }

36   public VirtualGiftCertificate this[int index]

37   {

38     get

39     {

40       return (VirtualGiftCertificate)virtualGiftCertificates[index];

41     }

42   }

43   public void Add(VirtualGiftCertificate vgc)

44   {

45     // Check to see if the VGC is already a member of a collection.

46     if (vgc.ParentOrderForm != null)

47       throw new ArgumentException("VGC already member of collection");

48     vgc.SetParent(this.parentOrderForm);

49     this.virtualGiftCertificates.Add(vgc);

50     parentOrderForm.SetChildDirty();

51   }

52   public void Remove(VirtualGiftCertificate vgc)

53   {

54     ...

55     virtualGiftCertificates.Remove(vgc);

56     vgc.SetParent(null);

57     parentOrderForm.SetChildDirty();

58   }

59 }

60 }  // End namespace MyOrdersClasses

 

Line 3: The class must be marked with the Serializable attribute.

Line 4: You must derive the collection from ICollection. Collections used in mapped storage and the Pipeline Adapter must implement list-style collection semantics instead of dictionary-style semantics. Implement ISerializable if you do not wish to use the default serializer. You do not need to derive the collection from MappedStorageBase since collection classes are not directly mapped for Orders storage.

Lines 6-7: The collection holds some internal data structure to hold the actual VirtualGiftCertificate instances, which uses an ArrayList. You also store a reference to the parent object.

Lines 8-12: You implement a custom constructor that you call from your new version of OrderForm.

Lines 13-17: A deserialization constructor is required for ISerializable support. This implementation is similar to the deserialization constructor you created for the VirtualGiftCertificate class.

Lines 18-23: GetObjectData is required for ISerializable support. See the full implementation in the sample code and the description for VirtualGiftCertificate.GetObjectData for more information. The security demand attribute shown is the minimum recommended for GetObjectData implementations.

Lines 24-35: You must implement the ICollection interface, including Count, SyncRoot, IsSynchronized, and GetEnumerator. This section shows a Count and GetEnumerator implementation. The GetEnumerator implementation must return a list-based IEnumerator (as opposed to an IDictionaryEnumerator).

Lines 36-42: If the collection internally is holding the items with an IList derived data structure, such as ArrayList, an indexer by integer index is mandatory.

Lines 43-51: This public Add method takes a single parameter of the object type that the collection holds. It calls VirtualGiftCertificate.SetParent with the collection's parent reference. This forces propagation of parent OrderForm ID and reference, and grandparent OrderGroupID, through the VirtualGiftCertificate (and any children, if VirtualGiftCertificate itself had collections of other classes). To prevent errors where a VirtualGiftCertificate is added to more than one collection, check for the parent reference to be null before adding the instance to the collection.

Lines 52-58: A public Remove method must exist that accepts the object to be removed. Call the parent SetChildDirty method when the removal succeeds. Set the parent on the removed object to null to be compatible with the Add logic and allow this instance to be added to a collection later.

 

Step 3: Derive a New OrderForm Class

 

In Visual Studio .NET, you derive a new OrderForm object and add the new virtual gift certificates collection as shown in the following code.

  Note

·         The line numbers appear for clarity; remove them before using this code.

1  namespace MyOrdersClasses

2  {

3  [Serializable]

4  public class MyOrderForm : OrderForm

5  {

6    private GiftCertificateCollection giftCertificates;

7    public MyOrderForm() : base()

8    {

9      giftCertificates = new GiftCertificateCollection(this);

10   }

11   public MyOrderForm(SerializationInfo info, StreamingContext context) : base(info, context)

12   {

13     this.giftCertificates = (GiftCertificateCollection)info.GetValue("GiftCertificates");

14   }

15   [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]

16   public override void GetObjectData(SerializationInfo info, StreamingContext context)

17   {

18     base.GetObjectData(info, context);

19     info.AddValue("GiftCertificates", this.giftCertificates);

20   }

21   public GiftCertificateCollection GiftCertificates

22   {

23     get

24     {

25       return giftCertificates;

26     }

27   }

28   public override void SetParent(object parentObject)

29   {

30     // We must call the base version to ensure propagation to base

31     // class members and collections.

32     base.SetParent(parentObject);

33

34     // Propagate the SetParent to the custom collection.

35     foreach (VirtualGiftCertificate vgc in this.giftCertificates)

36       vgc.SetParent(this);

37   }

38 }

39 }  // End namespace MyOrdersClasses

 

Line 3: The class must be marked with the Serializable attribute.

Line 4: New class MyOrderForm derives from the main Orders system OrderForm class.

Line 6: Add a private field to hold the new collection.

Lines 7-10: Override the default constructor and call the base constructor, adding a call to create your new collection.

Lines 11-20: Override the ISerializable interface members to handle the collection field. The GetObjectData security demand attribute is the minimum recommended for a GetObjectData implementation.

Lines 21-27: Expose a strongly typed property for the new collection.

Lines 28-37: You must override base SetParent implementation to ensure parent propagation occurs for all members of the added collection. You must invoke the base version of the function to ensure the propagation is performed for members of the base Orders class.

 

Step 4: Update the Storage Mapping File

You have created a new assembly containing your three new classes. Next, you must revise the Orders system storage-mapping file to account for the changes you made. The default version of the mapping file is stored in the virtual root of the CSharpSite sample site included with the CS2007, in the OrdersObjectMappings.xml file. When modifying this file you can choose to rename it to indicate that it is a custom version, and update the linkage in the Web.config file (the <MappingFiles> XML tag StorageMappingFilename attribute) for the site to point to the new file name. For this sample, you simply modify the existing file. The sample code contains a full, modified version of the file. The following excerpts from the file indicate the changes to be made.

Updates to Add the VirtualGiftCertificate Class

The following are changes that you must make to add the VirtualGiftCertificate class mapping information to the mapping file. Additionally, you update OrderForm to change its name and add its new collection member. Adding a class requires the addition of a new table, a new class definition, and mappings between the two. The following is the new table definition, which you place in the <Tables> section of the file:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1  <Table Name="VirtualGiftCertificates">

2   <Columns>

3    <Column Name="VirtualGiftCertificateID" DataType="int" />

4    <Column Name="OrderFormID" DataType="uniqueidentifier" IsNullable="false" />

5    <Column Name="GiftCertificateNumber" DataType="int" />

6    <Column Name="GiftCertificatePin" DataType="int" />

9    <Column Name="Price" DataType="money" />

10   <Column Name="BalanceAmount" DataType="money" />

11   <Column Name="OrderGroupID" DataType="uniqueidentifier" />

12  </Columns>

13  <Constraints>

14   <PrimaryKey Name="PK_VirtualGiftCertificates">

15    <ColumnRef Name="VirtualGiftCertificateID" />

16   </PrimaryKey>

17   <ForeignKey Name="FK_VirtualGiftCertificates_OrderForm" ForeignTable="OrderForms" CascadeDelete="true">

18    <ColumnMatch Name="OrderFormID" ForeignName="OrderFormID" />

19   </ForeignKey>

20  </Constraints>

21 </Table>

 

The table definition describes the columns and constraints on the table. The column definitions are straightforward, a translation from the class members to columns and their SQL data types. It is worth noting that not all class properties must map to a column if, for instance, a property is used during site code execution for temporary values.

The foreign key constraint listed in the table definition is required when you have a collection relationship between a parent and child class, and to enable use of relational integrity among the Orders classes. You store the parent OrderForm.OrderFormID in a column and create a foreign key relationship to the order form's table entry. Generated Orders storage stored procedure code takes into account any foreign key relationships when generating code to table rows from a hierarchy of objects.

Next, create the class definition. Add a new <Class> tag within the <Classes> section of the mapping file, as the following code shows:

<Class Name="VirtualGiftCertificate">

  <Property Name="VirtualGiftCertificateID" />

  <Property Name="GiftCertificateNumber" />

  <Property Name="GiftCertificatePin" />

  <Property Name="Price" />

  <Property Name="BalanceAmount" />

  <Property Name="OrderGroupID" />

  <Property Name="OrderFormID" />

</Class>

 

This class definition is straightforward. Include only the class members that you are mapping to storage; this definition is not intended to be a full duplication of the entire set of reflection information available about the class.

Then, add the mappings from class members to columns. You add a new <ClassTableMap> node to the <Mappings> section in the mapping file, as the following code shows:

<ClassTableMap Class="VirtualGiftCertificate" Table="VirtualGiftCertificates">

  <PropertyMap Property="OrderGroupID" Column="OrderGroupID" />

  <PropertyMap Property="OrderFormID" Column="OrderFormID" />

  <PropertyMap Property="VirtualGiftCertificateID" Column="VirtualGiftCertificateID" />

  <PropertyMap Property="GiftCertificateNumber" Column="GiftCertificateNumber" />

  <PropertyMap Property="GiftCertificatePin" Column="GiftCertificatePin" />

  <PropertyMap Property="BalanceAmount" Column="BalanceAmount" />

</ClassTableMap>

 

Updates for MyOrderForm

Start by modifying the information for OrderForm to point to your new class and include your new collection member. First, you modify the class definition for OrderForm:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Class Name="MyOrderForm">

2  <Property Name="OrderFormID" />

...

3  <Property Name="PromoCodeRecords" />

4  <Property Name="GiftCertificates" />

5 </Class>

 

On line 1, change the name OrderForm to MyOrderForm to change to the new class implementation. On line 4, add a new member entry for the new collection member GiftCertificates.

Next, modify the parent-child collection relationships for the classes. Rename instances of OrderForm to MyOrderForm, and add a new relationship (at line 6) to describe the one-to-many relationship between MyOrderForm.GiftCertificates and VirtualGiftCertificate, as shown in the following code:

1  <CollectionRelationships>

2   <CollectionRelationship Name="PurchaseOrderOrderForms"  ParentClass="PurchaseOrder" ParentProperty="OrderForms" ChildClass="MyOrderForm" />

...

3   <CollectionRelationship Name="LineItems" ParentClass="MyOrderForm" ParentProperty="LineItems" ChildClass="MyLineItem" />

...

4   <CollectionRelationship Name="OrderFormShipments" ParentClass="MyOrderForm" ParentProperty="Shipments" ChildClass="Shipment" />

5   <CollectionRelationship Name="OrderFormPromoCodeRecords" ParentClass="MyOrderForm" ParentProperty="PromoCodeRecords" ChildClass="PromoCodeRecord" />

6   <CollectionRelationship Name="OrderFormGiftCertificates" ParentClass="MyOrderForm" ParentProperty="GiftCertificates" ChildClass="VirtualGiftCertificate" />

7  </CollectionRelationships>

 

The Orders storage mapping system validates that, when such a relationship exists, there is also a foreign key relationship between the VirtualGiftCertificates and OrderForms tables. You added such a relationship in the table definition above.

Replace the old version of the mapping file in the virtual root of the site with this new copy.

Step 5: Modify the Orders Pipeline Mapping File

Changes to the Orders classes also require changing mapping information defined in OrderPipelineMappings.xml file. This file describes how instances of classes used with the Orders system are marshaled to and from legacy Commerce Server IDictionary instances for use with the legacy order pipeline. The changes required are similar in spirit, though not in format, to the changes made to the object-mapping file. The pipeline adapter does not translate PurchaseOrder, Basket, or OrderTemplate instances into IDictionary format, so you do not need to make any changes related to having one of those classes' OrderForms member point to your new MyOrderForm class.

First, you change the class name used for mapping OrderForm class instances to your new class, and then you add the new GiftCertificates collection. The following code shows the changes needed to the OrderForm class definition:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Class name="MyOrderForm">

2  <property name="OrderFormID" dictionaryKey="orderform_id"/>

...

3  <collection name="GiftCertificates" dictionaryKey="GiftCertificates" keyType="SimpleList" referTo="VirtualGiftCertificate" />

4 </Class>

 

Line 1 changes the definition of an OrderForm to a MyOrderForm. Line 3 adds the collection, with a reference to the VirtualGiftCertificate class.

Next, you add a definition for your new VirtualGiftCertificate class, as shown in the following code:

<Class name="VirtualGiftCertificate">

 <property name="VirtualGiftCertificateID" dictionaryKey="VirtualGiftCertificateID" classKey="true" />

 <property name="ShippingMethodID" dictionaryKey="shipping_method_id" />

 <property name="GiftCertificateNumber" dictionaryKey="GiftCertificateNumber" />

 <property name="GiftCertificatePin" dictionaryKey="GiftCertificatePin" />

 <property name="Price" dictionaryKey="Price" />

 <property name="BalanceAmount" dictionaryKey="BalanceAmount" />

</Class>

 

You use the classKey attribute on the VirtualGiftCertificateID property to find and update the class instance if it was created prior to being marshaled into an IDictionary to provide to the Orders pipeline. You should set the class key properties to the same as the set of primary keys used in the table definition in the class storage mapping—in this case, the ID.

 

Step 6: Modify the web.config File

You must modify the Web.config file Orders information to change the definition of LineItem to MyLineItem. The Web.config file contains an <Orders> section that contains a <Types> section. The Types section contains individual Type definitions that relate an Orders class to its current derived class name and provides information about the assembly to use to find the class. The following is the relevant Types section with the modifications you will need for this sample:

  Note

·         The line numbers appear for clarity; remove them before using this code.

1 <Types>

2  <Type Key="Basket" UserTypeName="Basket" AssemblyType="GAC" NameSpace="Microsoft.CommerceServer.Runtime.Orders" Assembly="Microsoft.CommerceServer.Runtime, Version=5.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

...

3  <Type Key="OrderForm" UserTypeName="MyOrderForm" AssemblyType="Local" NameSpace="MyOrdersClasses" Assembly="MyOrders"/>

4  <Type Key"VirtualGiftCertificate" UserTypeName="VirtualGiftCertificate" AssemblyType="Local" NameSpace="MyOrdersClasses" Assembly="MyOrders" />

...

5 </Types>

 

Line 2 shows a typical type definition for an original Orders type. A more complete description can be found in the Web.config file description.

At line 3, you change the OrderForm definition. The changes are similar to those made for the MyLineItem sample.

On line 4, you add a new definition for your new class. The Key attribute in this case is simply the name of the class—you have not derived VirtualGiftCertificate from a base Orders class. UserTypeName is also the same value. AssemblyType is Local since you have not added strong naming and GAC deployment of the assembly. NameSpace is the MyOrdersClasses namespace. Finally, the Assembly is the local-deployment assembly string for your assembly.

 

Step 7: Use OrderMapping.exe on the Storage File

See the notes from the MyLineItem sample on how to use OrderMapping.exe with the Web.config file and the assembly. You use the generated OrdersStorage.sql file to update the site database.

 

Step 8: Modify the Existing Database

In the CS2007, you perform modifications to existing tables. Assuming you apply this sample to the CSharpSite sample provided with the CS2007, this means adding the VirtualGiftCertificates table definition to the database.

CREATE TABLE [dbo].[VirtualGiftCertificates] (

  [VirtualGiftCertificateID] [INT] NOT NULL,

  [OrderFormID] [UNIQUEIDENTIFIER] NOT NULL,

  [GiftCertificateNumber] [INT] NULL,

  [GiftCertificatePin] [INT] NULL,

  [Price] [MONEY] NULL,

  [BalanceAmount] [MONEY] NULL,

  [OrderGroupID] [UNIQUEIDENTIFIER] NOT NULL

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

ALTER TABLE [dbo].[VirtualGiftCertificates] WITH NOCHECK ADD

    CONSTRAINT [PK_VirtualGiftCertificates] PRIMARY KEY CLUSTERED (

        [VirtualGiftCertificateID]

    ) ON [PRIMARY],

 

    CONSTRAINT [FK_VirtualGiftCertificates_OrderForm] FOREIGN KEY (

        [OrderFormID]

    ) REFERENCES [OrderForms] (

        [OrderFormID]

    ) ON DELETE CASCADE

GO

CREATE INDEX [IX_Ord_VirtualGiftCertificates_OrderGroupID] ON [dbo].[VirtualGiftCertificates] (

    [OrderGroupID]

) ON [PRIMARY]

GO

 

The table definition is straightforward. One noteworthy item is the addition of the index on OrderGroupID. All Orders classes must define a mapping to OrderGroupID even if it is not the direct parent. You use this value as a global key during storage loading and re-population of a PurchaseOrder and all of its contained children to look up all instances in all tables that correspond to a single, root PurchaseOrder instance. Therefore, it is advisable to add an index on that column for each table corresponding to an Orders class.

After adding the table definition, 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 9: Deploy the Assembly and Mapping Files

The MyLineItem sample describes the steps to deploy the assembly and the new versions of the mapping files.

 

 

Published Wednesday, June 28, 2006 10:04 AM by kumar vinod

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Vinod Kumar Joins Blogdom @ Thursday, June 29, 2006 7:33 PM

One of the core developers on Commerce Server has jumped onto the blogging bandwagon and that too with...

Nihit Kaul's WebLog

# re: Extending the Orders System @ Friday, June 30, 2006 12:12 AM

It's nice to see some excitement about CS2007, but considering how fast the commerce server team was to stop supporting any new technologies (sql 2005, aspnet 2.0) with CS2002 (you know, the one that is actually in an RTM state and licensed for use) I am leary of even thinking about getting it. What happens when something new tickles the teams fancy?

Bob

# re: Extending the Orders System @ Saturday, July 01, 2006 1:10 AM

This is a neat concept.  It cuts down a lot of code we wrote for our CS2002 implementation.  Any thoughts on why this wasn't implemented for the catalogue system?  It seems like a natural for this sort of extensibility.

Colin Bowern

# Commerce Server 2007: Some Great New Posts! @ Thursday, August 17, 2006 10:19 PM

Now that the Commerce Server development team has shipped their flagship product, they've started to publish some great new posts about using Commerce Server 2007. If you don't already subscribe to these blogs, you really should!

Jeff Lynch [MVP]

# re: Extending the Orders System @ Tuesday, September 19, 2006 1:01 AM

Can we use generics to eliminate the need of creating an collection class?

Colin Bowern

# re: Extending the Orders System @ Wednesday, September 27, 2006 11:10 AM

Excellent post! However, I'm having trouble extending the payment system. As an example, I want to support Paypal.

I think I need to add new tables and new classes to OrderObjectMapping.xml and orderPipelineMappings.xml also mention the new type in web.config. But how do I tell Commerce to use this for the Custom payment type? (or Custom1, Custom2, etc.)  I don't see where I can do that mapping.

Thanks for any leads.

Phil

# re: Extending the Orders System @ Thursday, September 28, 2006 9:43 PM

It would be great to see better type support in the future like nullable types and generics.  The more modern object persistence frameworks seem to be able to handle this.  Hopefully this functionality can move towards that (or by adopting some of the ORM work being done in the ADO.NET side of things).

Colin Bowern

# managing baskets using web services @ Monday, May 28, 2007 7:31 AM

Hi,

I need to use the orders web service provided by commerce server 2007 to add products to a basket in an e-commerce web site. can anyone give me pointers  regarding this. The orders web service doesnt seem to have any method to create a basket.

Thanks

Aparna

# Vkumar's Commerce WebLog : Extending the Orders System @ Monday, June 02, 2008 1:01 AM

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 Order

Dating

# Einkaufserlebnisse Ma??geschneidert - Webshop auf Basis der Commerce Server Startersite &laquo; blogbastlers - Taking eCommerce to the next level&#8230; @ Tuesday, November 25, 2008 6:10 AM

PingBack from http://blogbastlers.wordpress.com/2008/11/25/einkaufserlebnisse-masgeschneidert-webshop-auf-basis-der-commerce-server-startersite/

Einkaufserlebnisse Ma??geschneidert - Webshop auf Basis der Commerce Server Startersite &laquo; blogbastlers - Taking eCommerce to the next level&#8230;

# Vkumar s Commerce WebLog Extending the Orders System | Paid Surveys @ Friday, May 29, 2009 7:35 PM

PingBack from http://paidsurveyshub.info/story.php?title=vkumar-s-commerce-weblog-extending-the-orders-system

Vkumar s Commerce WebLog Extending the Orders System | Paid Surveys

# Vkumar s Commerce WebLog Extending the Orders System | storage bench @ Sunday, June 14, 2009 6:02 AM

PingBack from http://thestoragebench.info/story.php?id=46

Vkumar s Commerce WebLog Extending the Orders System | storage bench

# Vkumar s Commerce WebLog Extending the Orders System | fix my credit @ Tuesday, June 16, 2009 9:30 PM

PingBack from http://fixmycrediteasily.info/story.php?id=17348

Vkumar s Commerce WebLog Extending the Orders System | fix my credit

Leave a Comment

(required) 
required 
(required) 
Page view tracker