Developer forum

Forum » Development » GetProductById retrieves exception on IndexBuilderExtender

GetProductById retrieves exception on IndexBuilderExtender

Mario Santos Dynamicweb Employee
Mario Santos
Reply

Hi,

I am trying to get a product on IndexBuilderExtender using Dynamicweb.Ecommerce.Products.Product.GetProductById("PROD2546"), but it's always retrieving the following error:

Product index builder experienced a fatal error.. System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Environment.ExecutingContext.IsBackEnd() at Dynamicweb.Ecommerce.Products.Product.GetProductById(String productId, String productVariantId, String productLanguageId) at Dna.IndexBuilderExtender.IndexBuilderExtender.ExtendDocument(IndexDocument doc) at Dynamicweb.Ecommerce.Indexing.ProductIndexBuilder.WriteDocument(IndexDocument document, Int64 currentAutoId) at Dynamicweb.Ecommerce.Indexing.ProductIndexBuilder.ProcessProducts() at Dynamicweb.Ecommerce.Indexing.ProductIndexBuilder.Build(IIndexWriter writer, Tracker tracker)

I also tried to send the variant as an empty string, the default lang but got the same result. Any idea?

DW: 9.3.8

Thanks in advance!
BR, Mario


Replies

 
Nicolai Pedersen
Reply
This post has been marked as an answer

Hi Mario

You cannot. The index is built on a seperate thread that does not have any context. Asking for GetProductByID triggers a call to find the languageid from context and then things will break, because you have no context.

So you might be able to ask for the same data for a specific product, using the languageid. But basically the product object is currently not free from context dependencies, and can cause other kind of problems (i.e prices which are depending on users, currency etc.)

BR Nicolai

Votes for this answer: 1
 
Mario Santos Dynamicweb Employee
Mario Santos
Reply

Hi Nicolai

Makes sense, thanks for your help.

BR Mario

 
Lars Larsen
Lars Larsen
Reply

Hi Nicolai

I can confirm that trying to get the product using the productid and languageid results in the same problem! So what would then be the best way to get the product?

 
Nicolai Pedersen
Reply

Hi Lars

Depends and what you are trying to do - why would you want the product object?

Remember that the Indexbuilder extender gives you a document that already contains all the product information. So you already have access to the values of the product, see example below.

Using GetProductByID or select * from ecomproducts in these extenders is also a performance issue. Consider a solution with i.e. 100.000 products, this will trigger 100.000 db calls - at least, per indexing.

class IndexBuilderExtenderExample : IndexBuilderExtenderBase<ProductIndexBuilder>
    {
        public override void ExtendDocument(IndexDocument document)
        {
            if (document.ContainsKey("ID"))
            {
                string productid = (string)document["ID"];
            }

            if (document.ContainsKey("ProductNumber"))
            {
                string productNumber = (string)document["ProductNumber"];
                document.Add("ProductNumberCleaned", productNumber.Replace(".", string.Empty));
            }

            document.Add("CustomField", DateTime.Now);
        }
    }

 
Lars Larsen
Lars Larsen
Reply

Hi Nicolai

You're right, I will use the document from the index. I am upgrading a DW8 solution to DW9 and the DW8 code was originally made by a colleague. So I was not thinking so much about the logic rather that upgrading line by line!

Thanks.

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

I just ran into a similar situation: I use a SqlIndexBuilder (need to build my own for now as the extenders don't work for the SqlIndexBuilder) but I also need to be able to select products and add some product data to the indexed document (we're indexing publications that are associated with a produc). I found that inside the builder calling GetProductBySql isn't always safe indeed.

Do I have any options? Other than maybe doing a standard DataSet select against EcomProducts myself and filter out inactive products myself? I only need product fields, not category fields, so it might work, but I wonder if there's a cleaner solution....

Imar

 
Nicolai Pedersen
Reply
This post has been marked as an answer

GetProductsBySql is deprecated because it is context dependent. So you cannot use it in this scenario as there is no context. All the changes you are seeing to the Ecommerce APIs in the past year is related to get rid of that context.

GetProductsBySql has a version called (query As String, doRefactoring As Boolean, bulkFill As Boolean) that you call with SQL, false, false and it might work.

The product index builder also does not use the API for performance reasons. So maybe using the datatable is the best and safest option.

BR Nicolai

Votes for this answer: 1
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Thanks Nicolai. I ended up getting the products from the database directly.

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi,

 

Now that we have Services, couldn't we use them instead? I need to get the PrimaryOrFirstGroupId on the index (and it's name) and I was expecting to at least have the GroupId in the document already.

 

I am getting this error, but maybe that's because I am doing something wrong. This is Rapido's DB.

Error processing product (AutoID: 64757, ProductID: PROD7, VariantID: , LanguageID: LANG1, Name: Mongoose Tyax Comp Disc (#3)).. System.NullReferenceException: Object reference not set to an instance of an object.    at Dynamicweb.Ecommerce.Products.Product.set_ManufacturerId(String value)    at Dynamicweb.Ecommerce.Products.Product..ctor(Boolean paramToDistinguishAndIgnore)    at Dynamicweb.Ecommerce.Products.ProductRepository.ExtractProductInternal(IDataReader dataReader, Nullable`1& groupProductRelationSortingExists)    at Dynamicweb.Ecommerce.Products.ProductRepository.ExtractProduct(IDataReader dataReader, Nullable`1& groupProductRelationSortingExists)    at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId, Boolean useAssortments)    at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, Boolean useAssortments)    at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId)    at Dna.Rizzo.Extensions.IndexBuilderExtender.ExtendDocument(IndexDocument doc)    at Dynamicweb.Ecommerce.Indexing.ProductIndexBuilder.WriteDocument(IndexDocument document, Int64 currentAutoId, IIndexWriter writer, Tracker tracker)    at Dynamicweb.Ecommerce.Indexing.ProductIndexBuilder.ProcessProducts(SqlConnection connection, IIndexWriter writer, Tracker tracker)

 

Any way I can do that without doing direct DB calls?

 

Best Regards,

Nuno Aguiar

 

You must be logged in to post in the forum