Archive

Archive for octobre 2009

[Commerce Server] ProductConfiguration / CategoryConfiguration ou les oubliés de Commerce Server

Ces derniers temps, j’ai été sollicité sur des problématiques d’expertise Commerce Server qui m’ont permis de me rendre compte que 2 classes fondamentales pour tous développements Commerce Server étaient totalement méconnue, j’ai nommé:

Ces deux classes héritent toutes de la classe Microsoft.CommerceServer.Catalog.CatalogItemConfiguration, et elles sont utilisées pour ne charger que les éléments que vous avez besoin d’utiliser. En effet, il n’est pas rare lorsque vous souhaitez afficher une liste de produits, de ne vouloir afficher que certaines propriétés du produit sans avoir à utiliser ses variants, ses catégories parentes, etc., etc….

D’ailleurs, si vous jetez un œil sur l’API via Reflector, vous vous apercevez que la classe CategoryConfiguration ou ProductConfiguration est instanciée si vous n’en spécifiez aucune (ie, le framework choisit pour vous les choses à charger):

Pour illustrer l’importance de ces classes, prenons l’exemple de la récupération d’un produit ou nous n’avons besoin d’afficher que son prix et son descriptif:

  • Sans ProductConfiguration:
Product product = catalogCtx.GetProduct("Adventure Works Catalog", "AW029-03");
Console.WriteLine("Pid: " + product.ProductId + " - " + product.DisplayName + " - " + product.ListPrice);

Grâce au SQL Profiler, nous pouvons récupérer les appels SQL Server et se rendre compte qu’ici 2 procédures stockées sont appelées:

exec dbo.ctlg_GetProductProperties
     @BCName=N'Adventure Works Catalog'
    ,@fVirtualCatalog=0
    ,@oid=30
    ,@ProductUID_tmp=N'ProductCode'
    ,@VariantUID_tmp=N'VariantCode'
    ,@catalogname=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@eJoinType=-1
    ,@TargetTableName=N''
    ,@SourceJoinKey=N''
    ,@TargetJoinKey=N''
    ,@Columns_tmp=N'P.BaseCatalogName,CategoryName,P.oid,DefinitionName,IsSearchable,cy_list_price,UseCategoryPricing,i_ClassType,CatalogName,ProductId,OrigProductId,VariantId,OrigVariantId,PrimaryParentCategory,DisplayName,Timestamp,OriginalPrice,LastModified,ParentOId'
    ,@EnableInventory=1
    ,@InventoryServerName=NULL
    ,@InventoryDatabaseName=NULL
    ,@FilterOutOfStockProducts=0
    ,@FilterBackOrderableProducts=0
    ,@filterPreorderedSkus=0
    ,@UseThresholdAsFloor=1
    ,@TreatmissingAsOutOfStock=0
    ,@StockHandling=0

declare @p15 int
set @p15=3
exec dbo.ctlg_GetProductVariantProperties
    @fVirtualCatalog=0
    ,@catalogname=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@ProductID=N'AW029-03'
    ,@VariantID=N''
    ,@eJoinType=-1
    ,@TargetTableName=N''
    ,@SourceJoinKey=N''
    ,@TargetJoinKey=N''
    ,@BuiltInColumnsToReturn=N'BaseCatalogName,CategoryName,OrigCategoryName,P.oid,DefinitionName,IsSearchable,cy_list_price,UseCategoryPricing,i_ClassType,P.CatalogName,ProductId,OrigProductId,VariantId,OrigVariantId,PrimaryParentCategory,DisplayName,Timestamp,OriginalPrice,LastModified,rank,ParentOId'
    ,@OrderBy=N'[Rank]'
    ,@StartingRec=1
    ,@NumRecords=2147483646
    ,@SortAscending=1
    ,@RecordCount=@p15 output
    ,@ProductOID=30
    ,@EnableInventory=1
    ,@InventoryServerName=default
    ,@InventoryDatabaseName=default
    ,@FilterOutOfStockProducts=0
    ,@FilterBackOrderableProducts=0
    ,@FilterPreorderedSkus=0
    ,@UseThresholdAsFloor=1
    ,@TreatmissingAsOutOfStock=0
    ,@StockHandling=0
    ,@VariantUID=N'VariantCode'
select @p15

  • Via un ProductConfiguration:
ProductConfiguration pdtConf = new ProductConfiguration();
pdtConf.InventoryOptions = new Microsoft.CommerceServer.Inventory.InventoryOptions();
pdtConf.InventoryOptions.FilterBackorderableSkus = false;
pdtConf.InventoryOptions.FilterOutOfStockSkus = false;
pdtConf.InventoryOptions.FilterPreorderableSkus = false;
pdtConf.LoadAncestorCategories = false;
pdtConf.LoadCanonicalCategories = false;
pdtConf.LoadParentCategories = false;
pdtConf.LoadRelatedCategories = false;
pdtConf.LoadRelatedProducts = false;
pdtConf.LoadVariants = false;
Product product = catalogCtx.GetProduct("Adventure Works Catalog", "AW029-03", "en-US", pdtConf);
Console.WriteLine("Pid: " + product.ProductId + " - " + product.DisplayName + " - " + product.ListPrice);

Cette fois-ci nous pouvons constater qu’une seule procédure stockée est appelée (car nous ne remontons pas les variants):

exec dbo.ctlg_GetProductProperties
     @BCName=N'Adventure Works Catalog'
    ,@fVirtualCatalog=0
    ,@oid=30
    ,@ProductUID_tmp=N'ProductCode'
    ,@VariantUID_tmp=N'VariantCode'
    ,@catalogname=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@eJoinType=-1
    ,@TargetTableName=N''
    ,@SourceJoinKey=N''
    ,@TargetJoinKey=N''
    ,@Columns_tmp=N'P.BaseCatalogName,CategoryName,P.oid,DefinitionName,IsSearchable,cy_list_price,UseCategoryPricing,i_ClassType,CatalogName,ProductId,OrigProductId,VariantId,OrigVariantId,PrimaryParentCategory,DisplayName,Timestamp,OriginalPrice,LastModified,ParentOId'
    ,@EnableInventory=1
    ,@InventoryServerName=NULL
    ,@InventoryDatabaseName=NULL
    ,@FilterOutOfStockProducts=0
    ,@FilterBackOrderableProducts=0
    ,@filterPreorderedSkus=0
    ,@UseThresholdAsFloor=1
    ,@TreatmissingAsOutOfStock=0
    ,@StockHandling=0

En apparence , le ProductConfiguration nous a permi d’éviter l’appel à la procédure stockée qui nous remontait les variants. Mais jetez un oeil du côté des statistiques SQL pour vous apercevoir qu’il y a bien plus que cela:

  • Sans ProductConfiguration

    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘InventoryCatalogMap’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘InventoryCatalogMap’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CtlInv__Variants1__for_spid__60’. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 3, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogHierarchy’. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 3, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CtlInv__Variants1__for_spid__60’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

  • Avec ProductConfiguration

    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘InventoryCatalogMap’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Impressionnant non? 🙂 3 fois moins d’exécution côté SQL 🙂

Attaquons nous maintenant à la catégorie. C’est là ou les résultats sont les plus impressionnant (si si :))

  • Sans CategoryConfiguration
Category category = catalogCtx.GetCategory("Adventure Works Catalog", "Tents");
Console.WriteLine("Cid: " + category .Name+ " - " + category .DisplayName);
Côté SQL, nous constatons que 3 procédures stockées sont appelées :
exec dbo.ctlg_GetCategoryProperties
     @BCName=N'Adventure Works Catalog'
    ,@oid=3
    ,@catalogname=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@Columns_tmp=N'BaseCatalogName,CategoryName,OrigCategoryName,oid,DefinitionName,IsSearchable,cy_list_price,UseCategoryPricing,i_ClassType,CatalogName,ProductId,OrigProductId,VariantId,OrigVariantId,PrimaryParentCategory,DisplayName,Timestamp,OriginalPrice,LastModified,ParentOId'
    ,@fVirtualCatalog=0

declare @p13 int
set @p13=4
exec dbo.ctlg_GetProductsForCategory
     @CatalogName=N'Adventure Works Catalog'
    ,@language=N'en-US'
    ,@BCName=N'Adventure Works Catalog'
    ,@CategoryOid=3
    ,@ClassType=12
    ,@StartingRecord=1
    ,@NumRecords=500
    ,@OrderBy=N'[Rank]'
    ,@eJoinType=-1
    ,@TargetTableName=N''
    ,@SourceJoinKey=N''
    ,@TargetJoinKey=N''
    ,@RecordCount=@p13 output
    ,@PropertiesToReturn=N'*'
    ,@SortAscending=1
    ,@EnableInventory=1
    ,@InventoryServerName=NULL
    ,@InventoryDatabaseName=NULL
    ,@FilterOutOfStockProducts=0
    ,@FilterBackOrderableProducts=0
    ,@FilterPreOrderableProducts=0
    ,@UseThresholdAsFloor=1
    ,@TreatmissingAsOutOfStock=0
    ,@StockHandling=0
    ,@InventoryPropertiesToReturn=N'*'
    ,@fVirtualCatalog=0
select @p13

declare @p10 int
set @p10=0
exec dbo.ctlg_GetChildCategories
     @CatalogName=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@BCName=N'Adventure Works Catalog'
    ,@oid=3
    ,@StartingRec=1
    ,@NumRecords=500
    ,@PropertiesToReturn=N'*'
    ,@OrderBy=N'[Rank]'
    ,@SortAscending=1
    ,@RecordCount=@p10 output
    ,@fVirtualCatalog=0
select @p10

  • Avec un CategoryConfiguration: 
CategoryConfiguration catConf = new CategoryConfiguration();
catConf.InventoryOptions = new Microsoft.CommerceServer.Inventory.InventoryOptions();
catConf.InventoryOptions.FilterBackorderableSkus = false;
catConf.InventoryOptions.FilterOutOfStockSkus = false;
catConf.InventoryOptions.FilterPreorderableSkus = false;
catConf.LoadAncestorCategories = false;
catConf.LoadCanonicalCategories = false;
catConf.LoadParentCategories = false;
catConf.LoadRelatedCategories = false;
catConf.LoadRelatedProducts = false;
Category category = catalogCtx.GetCategory("Adventure Works Catalog", "Tents", "en-US", catConf);
Console.WriteLine("Cid: " + category .Name+ " - " + category .DisplayName);

Côté base de données, plus qu’un seul appel à une procédure stockée:

exec dbo.ctlg_GetCategoryProperties
     @BCName=N'Adventure Works Catalog'
    ,@oid=3
    ,@catalogname=N'Adventure Works Catalog'
    ,@Language=N'en-US'
    ,@Columns_tmp=N'BaseCatalogName,CategoryName,OrigCategoryName,oid,DefinitionName,IsSearchable,cy_list_price,UseCategoryPricing,i_ClassType,CatalogName,ProductId,OrigProductId,VariantId,OrigVariantId,PrimaryParentCategory,DisplayName,Timestamp,OriginalPrice,LastModified,ParentOId'
    ,@fVirtualCatalog=0

Grâce à la classe CategoryConfiguration correctement configurée, on a évité 2 exécutions de procédure stockée, mais vu côté statistique SQL c’est impressionnant! Jugé plutôt:

  • Sans CategoryConfiguration

Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__FirstLevelProducts__for_spid__59’. Scan count 0, logical reads 27, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 4, logical reads 8, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogHierarchy’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘InventoryCatalogMap’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__SecondLevelProducts__for_spid__59’. Scan count 0, logical reads 18, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__FirstLevelProducts__for_spid__59’. Scan count 5, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 8, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 4, logical reads 8, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__SecondLevelProducts__for_spid__59’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__ChildCategories__for_spid__59’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 4, logical reads 8, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogHierarchy’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CtlInv__ChildCategories__for_spid__59’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

  • Avec CategoryConfiguration

Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CatalogDefinitionPropertyList’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_en-US_Catalog’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Adventure Works Catalog_CatalogProducts’. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Quasiment 5 fois moins d’exécution SQL, pour un même résultat!!!!

Vous comprennez donc maintenant pourquoi il est très important de spécifier un CatalogItemConfiguration: il peut changer drastiquement les performances de votre site e-Commerce (et ceci même si vous utilisez le cache).

Pour ma part, si vous ne savez pas à l’avance quoi loader (c’est rarement le cas… j’espère ;)), je vous recommande plutôt d’opter pour du lazy loading, c’est à dire de configurer au minima (en gros je mets toutes les options à false) mon GetProduct ou GetCategory et laisse l’API charger les objets dont j’ai besoin.

Pour terminer, j’ai mis un petit graphique illustrant mes propos ou je me suis amusé à boucler 50 fois sur une récupération de Produit via un getProduct avec différentes options (pour info le cache était activé):

En bleu:

ctx.RefreshCache(); //refresh the catalogue cache system
for (int i = 0; i < 50; i++)
{
     chrono.Start();
     foreach (String pId in Constants.PRODUCTS)
     {
          Product p = ctx.GetProduct(Constants.CATALOGNAME, pId, "en-US");
     }
     chrono.Stop();
     long spent = chrono.ElapsedMilliseconds;
     chrono.Reset();
}

En rouge:

ctx.RefreshCache(); //refresh the catalogue cache system
ProductConfiguration pdtConf = new ProductConfiguration();
pdtConf.InventoryOptions = new Microsoft.CommerceServer.Inventory.InventoryOptions();
pdtConf.InventoryOptions.FilterBackorderableSkus = true;
pdtConf.InventoryOptions.FilterOutOfStockSkus = true;
pdtConf.InventoryOptions.FilterPreorderableSkus = true;
pdtConf.InventoryOptions.PropertiesToReturn = propertiesToReturn;

pdtConf.LoadAncestorCategories = true;
pdtConf.LoadCanonicalCategories = true;
pdtConf.LoadParentCategories = true;
pdtConf.LoadRelatedCategories = true;
pdtConf.LoadRelatedProducts = true;
pdtConf.LoadVariants = true;
pdtConf.ParentPropertiesToReturn = "*";
pdtConf.Variants.SearchOptions = new CatalogSearchOptions();
pdtConf.Variants.SearchOptions.PropertiesToReturn = "*";
for (int i = 0; i < 50; i++)
{
     chrono.Start();
     foreach (String pId in Constants.PRODUCTS)
     {
          Product p = ctx.GetProduct(Constants.CATALOGNAME, pId, "en-US", pdtConf);
     }
     chrono.Stop();
     long spent = chrono.ElapsedMilliseconds;
     chrono.Reset();
}

En vert:

ctx.RefreshCache(); //refresh the catalogue cache system
ProductConfiguration pdtConf = new ProductConfiguration();
pdtConf.InventoryOptions = new Microsoft.CommerceServer.Inventory.InventoryOptions();
pdtConf.InventoryOptions.FilterBackorderableSkus = false;
pdtConf.InventoryOptions.FilterOutOfStockSkus = false;
pdtConf.InventoryOptions.FilterPreorderableSkus = false;
pdtConf.InventoryOptions.PropertiesToReturn = propertiesToReturn;
pdtConf.LoadAncestorCategories = false;
pdtConf.LoadCanonicalCategories = false;
pdtConf.LoadParentCategories = false;
pdtConf.LoadRelatedCategories = false;
pdtConf.LoadRelatedProducts = false;
pdtConf.LoadVariants = false;
pdtConf.ParentPropertiesToReturn = "*";
pdtConf.Variants.SearchOptions = new CatalogSearchOptions();
pdtConf.Variants.SearchOptions.PropertiesToReturn = "*";

for (int i = 0; i < 50; i++)
{
     chrono.Start();
     foreach (String pId in Constants.PRODUCTS)
     {
          Product p = ctx.GetProduct(Constants.CATALOGNAME, pId, "en-US", pdtConf);
     }
     chrono.Stop();
     long spent = chrono.ElapsedMilliseconds;
     chrono.Reset();
}
 

Catégories :Commerce Server

[Commerce Server] Trier les propriétés Commerce Server selon des ordres de tri différents

Pour faire suite à une discussion sur le forum Commerce Server: How could i sort by property1 ASC and property2 DESC in a catalog search?, je me suis aperçu qu’une fonctionnalité de base de Commerce Server était mal comprise.

En effet, il n’est pas rare sur une liste de produits (ou de catégorie) de vouloir trier le résultat sur plusieurs critères et dans des sens différents tout en gardant la fonctionnalité de paging du CatalogSearch.

Ravi proposait pour solutionner cela d’utiliser un dataview. Le problème est que le dataview ne peut trier que sur le résultat de la recherche! Quid donc si vous avez plusieurs pages? Sans compter les piètres performances d’un dataview.

Pour solutionner cela, il suffit simplement de mettre le nom de votre propriété entre crochet [] puis de coller à la suite l’ordre du tri ex:

CatalogSearch catalogSearch = catalogContext.GetCatalogSearch();
catalogSearch.CatalogNames = "MyCatalog";
catalogSearch.SearchOptions.ClassTypes = CatalogClassTypes.ProductFamilyClass;
catalogSearch.SearchOptions.PropertiesToReturn = "ProductId, cy_list_price";
catalogSearch.CategoriesClause = "CategoryName = 'CatId";
catalogSearch.SqlWhereClause = "Display = 'OK'";
catalogSearch.SearchOptions.SortProperty = "[ProductId]ASC, [cy_list_price]DESC";

Attention, il est important qu’il n’y ait pas d’espace entre le crochet fermant et l’ordre de tri.

Pour info, notre expert en développement Commerce Server, Anoir, avait déjà écrit un article à ce sujet: Recherche d’un produit avec plusieurs colonnes de tris différenciés sur le blog d’Altima.

Catégories :Commerce Server

[TechEd 2009] Rencontrez les experts Commerce Server

Je serais présent du 9 au 13 novembre 2009 à Berlin pour les tech-ed EMEA. Durant cette semaine, vous pourrez me rencontrer ainsi que l’équipe Commerce Server aux Technical Learning Center (TLC). Le TLC est l’endroit où vous pourrez rencontrer les experts de toutes les technologies Microsoft, mais aussi de pouvoir “jouer” et dérouler les démos produits.

Durant ces tech-ed, une session Commerce Server est au programme. Elle aura lieu le 10 novembre 2009 (pour plus d’information: Build Custom E-Commerce Solutions Faster and Easier with Microsoft Commerce Server 2009 (OFS06-IS)

En espérant vous y croiser nombreux 🙂

Catégories :Uncategorized

[Windows 2008] Configurez facilement votre serveur Windows 2008 Core

Je suis tombé sur un outil vraiment très très très pratique: Core Configuration for Windows 2008 – Smart-X

Pour l’utiliser, il vous faut copier le msi sur votre serveur core et l’executer

Un petit reboot et zou vous allez pouvoir en un clic (ou deux) configurer votre réseau, ajouter un AD etc., etc.

  

N’en déplaise aux puristes de la ligne de commande, mais c’est diablement pratique 😉

Seul petit bémol, cet outil n’est disponible qu’en mode non commercial, ie pas sur vos serveurs de production…

Bon amusement

Catégories :Windows