Querying inherited page types when using generated page type class

699 views Asked by At

I am attempting to use TreeProvider to query pages which all inherit from a base page type, here referred to as My.Product. I have also integrated the generated C# class for that base page type in order to get strongly-typed access to page type values.

The following query, without using the generated page type, works fine:

        //returns all products as TreeNode
        var products = tree.SelectNodes()
            .OnSite("MyWebSite")
            .Types("My.Product*")

Using the generated type with the generic version of SelectNodes, the Types extension can't be used, and no pages are returned. I assume because the inherited page types are not included.

        //returns nothing
        var products = tree.SelectNodes<Product>()
                           .OnSite("MyWebSite");

Based on this answer I tried a cast:

        var products = tree.SelectNodes()
            .OnSite("MyWebSite")
            .Types("My.Product*")
            .ToList()
            .Cast<Product>();

But the cast failed:

Unable to cast object of type 'CMS.Ecommerce.SKUTreeNode' to type 'CMS.DocumentEngine.Types.Product'.

I've also tried constructing the page type object from the results of the query:

        var products = tree.SelectNodes()
            .OnSite("MyWebSite")
            .Types("My.Product*")
            .ToList()
            .Select(x => TreeNode.New<Product>(null, x, tree))
            .ToList();

But the API doesn't like the class name mismatch:

Input class name 'My.ProductInheritingType is not consistent with the requested type 'CMS.DocumentEngine.Types.Product' which has class name 'My.Product'. To fix this, use correct class name or null as the input parameter.

Is there a way to use TreeProvider with my strongly typed page type, and retrieve pages which use inheriting page types?

2

There are 2 answers

4
Trevor F On

You can use the .WhereEquals("ClassInheritsFromClassID",TheMyProductClassID) to get all classes that inherit from that class. That will probably be the best route. Below should be approximately the right syntax.

int MyProductClassID = DataClassInfoProvider.GetClassInfo("My.Product").ClassID;
var AllInheritedClassIDs = DataClassInfoProvider.GetClasses().WhereEquals("ClassInheritsFromClassID", MyProductClassID).Select(x=> x.ClassID).ToList();

var products = tree.SelectNodes()
            .OnSite("MyWebSite")
            .WhereIn("NodeClassID", AllInheritedClassIDs);
            .ToList();
0
nickwesselman On

I don't know if this is the best approach, but it's working at the moment. There were several problems to overcome:

  1. Querying all the inheriting types
  2. Ensuring the returned data included all the needed columns
  3. Mapping into the page type class

For the last item above, I couldn't find a way to get the Kentico API to initialize my base Product type if the document class name did not match. So I had to extend the generated class and call into a protected initialization method:

public partial class Product
{
    public void Initialize(IDataContainer data, TreeProvider treeProvider)
    {
        base.Initialize(this.ClassName, data, treeProvider);
    }
}

I could then construct and initialize this class in a LINQ statement that also includes querying for all the inheriting types of my base page type, with all their supporting data columns using the DocumentHelper API instead of the TreeProvider.

        var classId = DataClassInfoProvider.GetDataClassInfo("My.Product").ClassID;
        var productClasses = DataClassInfoProvider.GetClasses()
                                                  .WhereEquals("ClassInheritsFromClassID", classId)
                                                  .ToList();

        var products = DocumentHelper.GetDocuments()
                                       .OnSite("MyWebSite")
                                       .Types(productClasses.Select(x => x.ClassName).ToArray())
                                       .WithCoupledColumns()
                                       .ToList()
                                       .Select(x =>
                                       {
                                           var product = new Product();
                                           product.Initialize(x, tree);
                                           return product;
                                       })
                                       .ToList();