SuperOffice 9.2 R07 - ExtenderExtender changes

Hi

I'm trying to upgrade an existing Contact ExtenderExtender from SuperOffice 8.5 to SuperOffice 9.2R07 (the latest version) and are having trouble to get it to work.  I have read the article from Tony about how to use the Find API (https://community.superoffice.com/en/content/content/netserver-sdk/netserver-9.x/superoffice-find/), but I can't see that this explains changes that affect ExtenderExtender. But, please let me know if there are something I don't see...

To make sure no other code can affect my EE, I tested this code on a blank 9.2R07 installation:

[ArchiveExtenderExtender("CrmiContactExtenderExtender", typeof(CombinedContactExtenderBase), int.MaxValue / 2)] 
  public class CrmiContactExtenderExtender : TableExtenderBase<ContactTableInfo>
{
  protected const string ColumnNameTitle = "crmiTitle";
  protected ArchiveColumnInfo _colTitle = new ArchiveColumnInfo(ColumnNameTitle, "Title", "Title", Constants.DisplayTypes.String, true, true, "10c", Constants.RestrictionTypes.String);

  public CrmiContactExtenderExtender()
  {
     _colTitle.IconHint = "CRMI";
  }

  protected override void InnerModifyQuery()
  {
      // My code to mapp return fields
  }

  protected override ContactTableInfo SetJoin()
  {
    var contactTi = (ContactTableInfo)Parent.TableToExtend;

    // My custom join criterias
      
    return contactTi;
  }
}

I intentionally left out my custom code for the methods InnerModifyQuery and SetJoin. 

When adding the DLL to SuperOffice, the new criteria is visible inside Find/Selection:

So, my EE are read by SuperOffice and the constructor is called. Before starting SuperOffice I have attached Visual Studio to the IIS process running SO92 R07 to verify this.

If I now use my custom Title criteria and specify something like this:

and press Find button. Neither SetJoin nor InnerModifyQuery are called (I have breakpoints in my code). It looks like SuperOffice just ignore my EE. Why?

Is the use of CombinedContactExtenderBase as extender class "invalid"? Based on this forum post from 2017 (https://community.superoffice.com/en/developer/forum/rooms/topic/netserver-api-group/core-components/extending-an-archive-to-include-extrafield/) Marek says: 

"... In the meantime, a possible, partial solution is to use the FindContactExtender as the target, instead of ContactExtenderBase. That works in Find, but not everywhere else. Another possible target is the CombinedContactExtenderBase, which is further up the hierarchy and gives you Find as well as Selection functionality. ..."

I have similar EE for Person where I use CombinedPersonExtenderBase, and they work as expected.

Any ideas will be appreciated. Thank you

 

RE: SuperOffice 9.2 R07 - ExtenderExtender changes

Hi Arild,

First, I have to come with the obligatory reminder that this kind of thing won't work in Online, and that's where our (and your) customers are heading.

Ok... next thing: contact/person search was a desperately complicated thing, due to its "maybe it's a person, maybe it's a contact" dual nature. Adding contact-without person and person-without-contact made it really hard, forcing us to use a RIGHT OUTER JOIN, which in effect gives as a query with multiple roots (argh).

When we revamped Selection, and made Find into a Dynamic Selection (it's 100% the same now, the only thing is that you can't see that dynamic selection anywhere in the UI), we also reorganized the structure of the providers behind it. That was motivated both by the new OR functionality, and a wish to avoid the Right Join (which could cause performance disasters).

That means goodbye to the Right join, and it means that the CombinedContactExtenderBase doesn't play the same role as it used to. I've created a test that mimics what is happening, and get the same behaviour as you observe. It's still more complicated than we like it to be, and we are actively considering whether to stop mixing these two entities into one - not least now that the user interface in Find discriminates between them in its entry page.

If you latch on to typeof(ContactExtenderBase) you do get called properly. You may then have to add some logic (for instance, checking the Parent.GetType()) to determine your place in the extender hierarchy, in case you want to limit where any criteria should be presented or processed. If the parent is a SelectionDynamicContactExtender then you probably are where you want to be.

There's all kinds of internal logic and pruning going on, to handle the contact/person duality and that's why it's all so hard to work with. My crystal ball is cloudy as usual, but if we decide to pick those entities apart then I will be very happy; and your customization will have to be rewritten a bit again.

ExtraFields added through Service are now discovered and shown, when they are directly on a target table like contact or person. With the Upsert mass operation API it's feasible to maintain such fields on a large scale as well. I would strongly recommend considering a solution in that direction, rather than the ArchiveExtenderExtenders. They were a good tool for their time, but they're not the way forward.

 

Marek

 

Av: Marek Vokáč 11. maj 2021

RE: SuperOffice 9.2 R07 - ExtenderExtender changes

Hi Marek

Thank you for your comment. Using ContactExtenderBase seems to work better, but I still have some trouble getting it to work as expected. The problem is that an Inner Join against Relations are for some reason added by SuperOffice, and this join "corrupts" the query against the database.

Here is my new code where two checks are added to make sure my extender are only used for SelectionDynamicContactExtender:

[ArchiveExtenderExtender("CrmiContactExtenderExtender", typeof(ContactExtenderBase), int.MaxValue / 2)] 
  public class CrmiContactExtenderExtender : TableExtenderBase<ContactTableInfo>
{
  protected const string ColumnNameTitle = "crmiTitle";
  protected ArchiveColumnInfo _colTitle = new ArchiveColumnInfo(ColumnNameTitle, "Title", "Title", Constants.DisplayTypes.String, true, true, "10c", Constants.RestrictionTypes.String);

  public CrmiContactExtenderExtender()
  {
     _colTitle.IconHint = "CRMI";
  }

  protected override void InnerModifyQuery()
  {
      if (Parent.GetType().Name != "SelectionDynamicContactExtender") return;

      // My code to map return fields
  }

  protected override ContactTableInfo SetJoin()
  {
    if (Parent.GetType().Name != "SelectionDynamicContactExtender") return null;

    var contactTi = (ContactTableInfo)Parent.TableToExtend;

    // My custom join criterias
      
    return contactTi;
  }
}

Using SQL Server Profiler, I can see that three inner joins are added to the query:

...
FROM       crm7."CONTACT" T0
INNER JOIN crm7."RELATIONS" T1 ON ( T0."contact_id" = T1."source_record"
      AND ( T1."source_table" = 5 )AND ( T1."destination_table" = 5 ) )
INNER JOIN crm7."RELATIONS" T2 ON ( T0."contact_id" = T2."destination_record"
      AND T2."destination_table" = 5 )
INNER JOIN crm7."CONTACT" T3 ON ( T2."source_record" = T3."contact_id"
      AND T2."source_table" = 5 )
...

Why are the relations tables added and how can I remove them or at least make sure they are set as Left Outer Join?

Arild

 

Av: Arild Eik 18. maj 2021

RE: SuperOffice 9.2 R07 - ExtenderExtender changes

The joins are added because there are ContactExtenders representing company relations; and they are INNER because the system detected a match with your field as a restriction. This is all handled by the base class, and it doesn't know that you don't want to match there.

I think the solution is to override SetRestriction(...). If you return false it means "no matches here, move along"; so if you put another of those Parent.GetType().Name tests there, you should be able to avoid those joins.

Av: Marek Vokáč 18. maj 2021

RE: SuperOffice 9.2 R07 - ExtenderExtender changes

I tried earlier to override the SetRestriction(...) and return false if the parent name was unequal to "SelectionDynamicContactExtender". It did not work.

So I did some more testing and found out that you also need to return true if the parent name is "ContactContactExtender". Like this:

public override bool SetRestriction(params ArchiveRestrictionInfo[] restrictions)
{
  if (Parent.GetType().Name != "SelectionDynamicContactExtender" && Parent.GetType().Name != "ContactContactExtender") return false;

  // Do my stuff here     
  
  return true;
}

Now it works as expected! I get data in return and the queries in SQL Server Profiler looks good....

But, when I add my extender column as a display column in the result view tab I get a SCIL error: :(

Anyway, thank you for the help Marek. 

 

Av: Arild Eik 19. maj 2021