Gael's profileGael Duhamel - SharePoin...PhotosBlogListsMore Tools Help

Blog


    November 06

    [Commerce Server 2009] La dernière CTP de Commerce Server 2009 R2 est disponible

    Récemment, la team Commerce Server a publié la dernière CTP de Commerce Server 2009 R2.  Comme vous vous en doutez, je me suis empressé de l’installer pour découvrir les nouvelles features et les partager avec vous.

    Tout d’abord, vous pouvez dire adieu à vos vieux processeurs 32 bits puisque Commerce Server 2009 R2 ne tournera que sur du 64bits! Idem pour vos windows 2003 ou SQL 2005. La R2 ne supporte que Windows 2008 (R2 ou non) et SQL Server 2008 (R2 ou non).

    Mon premier retour est plus que positif! De nombreux points ont été considérablement amélioré. Commençons par l’installation où tout a été repensé. Nous avons maintenant beaucoup plus de souplesse sur la sélection des composants à installer:

    image image image

    Sur la configuration de Commerce Server, un effort a aussi été fait pour vous guider au mieux. 2 choses à dire ici:

    • Pour le moment, seule la configuration de base est activée. L’option avancée viendra dans une future version
    • Il y a un bug si vous souhaitez utiliser un serveur SQL distant. Pour le moment, seul une installation en mode SQL locale fonctionne via l’outil. Pour contourner le problème, il vous faut lancer vous même la configuration via une ligne de commande et un fichier XML.
    C:\Program Files (x86)\Microsoft Commerce Server 9.0>CSConfigWizard.exe /s ConfigLaunch.xml
    <Configuration>
      <SQL ID="CommerceAdminDB">
        <Server>RemoteSQLServer</Server>
        <Database>MSCS_Admin</Database>
        <WindowsSecurity>yes</WindowsSecurity>
      </SQL>
      <SQL ID="DirectMailerDB">
        <Server>RemoteSQLServer</Server>
        <Database>DirectMailer</Database>
        <WindowsSecurity>yes</WindowsSecurity>
      </SQL>
      <NTService ID="DirectMailerService">
        <UserName>CSService</UserName>
        <Domain>SPGAEL</Domain>
        <Password>password</Password>
      </NTService>
      <VirtualDirectory ID="Publishing" Create="False" />
      <NTService ID="StagingService">
        <UserName>CSService</UserName>
        <Domain>SPGAEL</Domain>
        <Password>password</Password>
      </NTService>
    </Configuration>

    Concernant la mise en place du template Storefront, rien de particulier à dire pour les habitués de Commerce Server:

    • Méthode manuelle:
      • Unpup
      • Gestion de la sécurité et des utilisateurs
      • Configuration des webservices
      • Deployer les solutions SharePoint
    • Méthode assistée:
      • %commerce_server_root%\SharePointServices\Site\SharePointCommerceServicesConfiguration.exe
        • j’ai eu pas mal de problèmes avec le SharePointCommerceServicesConfiguration dans la version de Commerce Server 2009, qui m’ont fait privilegié la méthode déploiement/configuration manuelle. Sur la R2, le process a été amélioré car j’ai tenté plusieurs déploiement qui ceux sont tous déroulés avec succès :) Encore un bon point pour la R2

    Notez au passage, que layout du site n’a pas beaucoup évolué mais propose quelques trucs sympa comme la configuration des catalogues utilisés/channel

    image

    Attention de nombreuses assemblies ont été modifiées. Consultez bien la documentation de la R2 qui explique cela en détail! Ne vous étonnez donc pas des effets de bord lors des déploiements de votre environnement Commerce Server 2009.

    Technorati Tags: ,,
    October 26

    [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):

    image image

    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();
    }
    image 

    [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.

    August 02

    [Commerce Server] Le Data Warehouse & les analytics reports

    Commerce Server offre dans sa version entreprise une suite analytics basée sur un Data Warehouse made by Commerce Server.

    Dans ce post, je vais donc m’atteler à vous expliquer comment paramétrer tout cela et vous donner un aperçu des différents rapports.

    Avant de démarrer votre installation, il vous faut avoir configurer et installer:

    • SQL Server Analysis Services (SSAS)
    • SQL Server Reporting Services (SSRS)
    • SQL Server Integration Services (SSIS)

    Puis vérifié ces pré requis:

    Nous allons donc maintenant “dépuper” le fichier de ressource du Data Warehouse (le fichier se trouve sur %commerce_server_root%\Pup Packages\DW.pup). Cette ressource va créer la base de données qui servira de référentiel pour notre cube.

    Attention: si vous installez votre Data Warehouse dans une autre langue que l’anglais vous devez impérativement modifier le fichier %commerce_server_root%\Data\CommerceOlap.xmla à la ligne 9679, en remplaçant le texte “Everyone” par “Tout le monde” pour les francophones.

    <Roles>
      <Role>
        <ID>All Users</ID>
        <Name>All Users</Name>
        <Members>
          <Member>
            <Name _loc="locData">EveryoneTout le monde</Name>
          </Member>
        </Members>
      </Role>
    </Roles>

    Commerce Server - Add Data Warehouse ressourece: Commerce Server Manager Commerce Server - Add Data Warehouse ressourece: Open DW.Pup Commerce Server - Add Data Warehouse ressourece: Select the Data Warehouse ressource Commerce Server - Add Data Warehouse ressourece: Use a new ressource Commerce Server - Add Data Warehouse ressourece: Confirm the parameter Commerce Server - Add Data Warehouse ressourece: rocking ;) Commerce Server - Add Data Warehouse ressourece: give a name to the ressource Commerce Server - Add Data Warehouse ressourece: still rocking Commerce Server - Add Data Warehouse ressourece: yeah Commerce Server - Add Data Warehouse ressourece: confirmation Commerce Server - Add Data Warehouse ressourece: Proof :)

    Une fois la structure du Data Warehouse et les cubes mis en place, nous allons installer les rapports. Pour cela, ouvrez le Command Prompt de Commerce Server, et tapez “ReportInstaller.exe”:

    Commerce Server - Import de reports: Open the shell Commerce Server - Import de reports: run the program

    Sur la boite de dialogue, renseignez les champs et testez les en cliquant sur “Test Connection”. Si tout est ok, cliquez sur “Install Reports”

    Commerce Server - Import de reports: set the report Commerce Server - Import de reports: report server Commerce Server - Import de reports: list of reports

    Il est maintenant temps de configurer les différentes permissions pour le compte DTSImport pour nos bases de données:

    • MSDB
      • db_datareader, db_dtsadmin, db_dtsltduser , db_dtsoperator
    • <nomDuSiteCommerceServer>_DataWarehouse
      • db_datareader, db_datawriter, db_owner, db_ddladmin
    • <nomDuSiteCommerceServer>_marketing
      • db_datareader
    • <nomDuSiteCommerceServer>_marketing_lists
      • db_datareader
    • <nomDuSiteCommerceServer>_productcatalog
      • db_datareader
    • <nomDuSiteCommerceServer>_profiles
      • db_datareader, Profile_Schema_Reader
    • <nomDuSiteCommerceServer>_transactionconfig
      • db_datareader
    • <nomDuSiteCommerceServer>_transactions
      • db_datareader

    Ajoutez ensuite cet utilisateur au groupe administrateur de votre serveur SSIS/SSAS.

    Pour terminer l’installation, nous devons importer les DTS à la mode 2000. Pour cela, il nous faut lancer le Data Warehouse Import Wizard. Il n’est pas nécessaire de lancer l’import des données dans ce wizard car il peut-être fais ensuite.

    Sauvegardez les donc dans la base de données SQL Server:

    Commerce Server - Import dts wizard: Open Commerce Server - Import dts wizard Commerce Server - Import dts wizard: select a Commerce Site Commerce Server - Import dts wizard: Commerce Server - Import dts wizard Commerce Server - Import dts wizard Commerce Server - Import dts wizard Commerce Server - Import dts wizard

    Pour ouvrir et exécuter le DTS, rendez-vous dans le serveur SQL: SSMS > Gestion > Existant > DTS

    Commerce Server - Import the data Commerce Server - Import the data Commerce Server - Import the data

    Dernière étape, la génération des cubes. Pour cela, il suffit d’ouvrir le SQL Server Business Intelligence Development Studio:

    image image

    Et traiter l’ensemble des cubes et dimensions:

    image image image

    That’s it’s that’s all! Vous pouvez maintenant contempler vos chefs d’œuvres :)

    Commerce Server Report: Product Sales

    Commerce Server Report: Customer Sales

    Commerce Server Report: Order Events

    image

    Si vous souhaitez changer la zone horaire ou le jour de démarrage de la semaine dans vos rapports, il suffit de vous rendre dans les propriétés du DW des ressources globales:

    Commerce Server Data Warehouse: Set the local time 

    Pour aller un peu plus loin, je vous conseille la lecture de ces articles qui vous aideront à bien comprendre le pourquoi/comment de l’analytics made by Commerce Server:

    Technorati Tags: - - -

    August 01

    [Commerce Server] Problème avec la planification de Commerce Server Staging

    J’ai découvert un petit bug, lors de la mise en place de la planification d’un projet “Business Data” avec Commerce Server Staging (CSS). Ce bug se déclenche lors de la création par CSS de la tâche planifiée windows.

    Pour planifier mon projet de staging, j’ai utilisé la mmc de CSS:

    Commerce Server Staging - Planification d'un projet

    Une fois cet écran validé, CSS va automatiquement créer (ou mettre à jour), une tâche planifiée windows:

    Planificateur de tâches

    Le problème est que sur cette création ou modification de la planification, les paramètres de bases de la tâches sont incorrect. si vous éditez la tâche planifiée, vous verrez que l’appel au programme est incorrect:

    Propriété d'une tâche planifiée

    L’appel au programme n’est pas entouré de guillemet (“). Ce qui fait que la tâche va essayer d’exécuter “c:\program” avec comme argument “Files (x86)\Microsoft Commerce Server 2007\Staging\Bin\CSS.exe”...

    Pour remédier à cela, il vous suffit donc tout simplement de mettre les guillemets smile_regular, soit:

    c:\program Files (x86)\Microsoft Commerce Server 2007\Staging\Bin\CSS.exe

    Pour terminer et pour information, votre tâche va automatiquement s’exécuter sous le compte par défaut du CSS. si vous souhaitez le modifier, vous devez le faire dans la configuration de votre tâche planifiée. Dans les 2 cas, vérifiez que votre compte à les privilèges d’ouvrir une session en tant que tâche.

    Statégie de sécurité locale 

    Attention: Sur l’événement de création ou modification, la tâche est recréée complètement. Pensez donc à bien vérifier la configuration de votre tâche planifiée à chaque modification de la planification de votre projet.

    Technorati Tags: - - -

    July 01

    Je suis MVP Commerce Server :)

    J’ai reçu cet après midi un email de la part de Microsoft m’annonçant ma nomination au programme MVP. C’est donc un grand plaisir pour moi et une belle récompense pour le travail effectué. A moi, donc de continuer à travailler pour pouvoir rédiger un autre post de ce type dans 1 an.

    Je tiens aussi à remercier les membres de la team Commerce Server d’ ainsi que nos différents clients sans qui tout cela n’aurait pas été possible smile_regular

    May 14

    [Commerce Server] Camaieu boutique – Prêt à porter féminin et vêtement mode en ligne

    La team Commerce Server d’Altima est heureuse de vous annoncer la sortie du nouveau site eCommerce de Camaieu.

    A vos cartes bleues smile_regular

    clip_image002

    Technorati Tags: - - - -

    April 22

    [Commerce Server] 2 webcasts autour des possibilités/capacités de Commerce Server

    Si vous avez un peu de temps en fin de journée ce jeudi 23 avril, je vous conseille de regarder 2 webcasts sur Commerce Server.

    La première webcast sera animée par Victor Castro de Commerce Generation: Green Up Your Business Online with Virtual Gift Cards for Customer Retention and Brand Loyalty by Commerce Generation. Cette webcast expliquera comment les cartes cadeaux peuvent aider à augmenter les ventes d’un site eCommerce. Vous verrez aussi comment l’implémenter dans une solution Commerce Server.

    La deuxième webcast sera animée par la société Cactus Commerce et tournera autour de la stratégie Multi Channel de Commerce Server 2009: Cross-Channel Retail and the Mobile Experience. Vous pourrez ainsi voir les possibilités qu’offre Commerce Server 2009 dans votre stratégie mCommerce.

    CommerceServer2009

    Tags: - - - - -

    March 26

    [Commerce Server 2009] Retour sur le MIX 2009

    Le MIX 2009 a été l’occasion d’officialisé la sortie de la dernière version de Commerce Server dans sa mouture 2009. A cette occasion Jean-Yves Martineau le fondateur de Cactus Commerce et Scott Cairney son vice président ont réalisé une session passionnante sur la nouvelle génération de leur plate-forme eCommerce (visible sur le site du MIX: Creating a "Next Generation" E-Commerce Experience).

    Je profite de ce post pour promouvoir les sites et ressources officielles (toutes en anglais, pas de version française pour le moment):

     

    Picture1

    Tags:

    March 03

    [Commerce Server] Commerce Server 2009

    Ca y est! Après quelques mois de gestation, la nouvelle version de Commerce Server est disponible à la vente. Adieu donc à Mojave et bienvenue à Commerce Server 2009. La nouvelle version s’accompagne même d’un site remis à jour tant au niveau du contenu que du design: le luxe smile_regular.

    Côté licence, pas de gros changement puisqu’il est toujours disponible en version Standard et Entreprise. Les fonctionnalités restant les mêmes. Le gros du travail a été fait dans les API de Commerce Server ainsi que le couplage avec SharePoint aux travers d’une série de web part. Pour le détail des fonctionnalités: Commerce Server 2009 Features.

    Microsoft Commerce Server 2009

    Tags: