24 Replies Latest reply on Mar 8, 2016 4:37 PM by MaximeHT

    FindElementsByAttribute with AFEnumeration query attribute

    MaximeHT

      With AFSDK V2.6, the FindElementsByAttribute function dosn't seem to work when at least one of the query attributes is typed AFEnumerationSet.

       

      Is there another way to get the following code working?

       

       

      try

                  {

                      listeDonnees.Clear();

       

                      PI_MessageLogger.GetInstance().WriteDebug("Chargement dans " + this.cheminElementRacine);

                      AFElement elementAF_Racine = this.interface_PIAF.AFDB.Elements[this.cheminElementRacine];

       

                      do

                      {

                          // Find the elements and load the attributes we will be using.

                          AFAttributeValueQuery avq1 = new AFAttributeValueQuery(template.AttributeTemplates["Code_point_de_réference"], searchOperator, "IR0010");

                          AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Type_de_donnée"], searchOperator, "Indice de Wobbe");//TEST 1) Type = AF Enumeration  ==> DOESN'T WORK !!!!!!

                          //AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Publication_active"], searchOperator, true);//TEST 2) Type = Boolean ==>  WORKS !

       

                          AFAttributeValueQuery[] attributeValueQueryTable = new AFAttributeValueQuery[2] { avq1, avq2};

       

                          AFNamedCollectionList<AFElement> myElements = AFElement.FindElementsByAttribute(elementAF_Racine, "*" , attributeValueQueryTable, searchFullHierarchy, AFSortField.Name, AFSortOrder.Ascending, maxCount);

       

                          if (myElements == null) // --> Count = 0 if AF Enumeration is used!!!!

                          {

                              break;

                          }

                          else

                          {

                              // Once the elements are loaded, we can process them.

                              this.chargerListeAvecElements(listeDonnees, myElements);

       

                              startIndex += pageSize; // Advance to next page.

                          }

                      } while (startIndex < this.totalCount);

       

                  }

                  catch (ThreadAbortException ex)

                  {

                      throw ex;

                  }

                  catch (Exception ex)

                  {

                      foundOK = false;

                      PI_MessageLogger.GetInstance().WriteException(new System.Diagnostics.StackFrame(), ex, "Une exception est survenue durant la lecture des données AF.");

                  }

       

       

      Thanks

        • Re: FindElementsByAttribute with AFEnumeration query attribute
          bshang

          You probably need to pass in an AFEnumerationValue into the object accepted by the AFAttributeValueQuery constructor, instead of a string. Two enumeration sets can have the same named state. If the search were to only accept a string as the state, it would not be possible to determine which enumeration set was desired.

          AFEnumerationValue s = ps.Databases["Sandbox"].EnumerationSets["Enum1"]["Value1"];

            • Re: FindElementsByAttribute with AFEnumeration query attribute
              MaximeHT

              Hi Barry,

               

              I tried that way, but it doesn't work anymore :

               

              try

              {

              listeDonnees.Clear();

               

              PI_MessageLogger.GetInstance().WriteDebug("Chargement dans " + this.cheminElementRacine);

              AFElement elementAF_Racine = this.interface_PIAF.AFDB.Elements[this.cheminElementRacine];

               

              do

              {

                     // Find the elements and load the attributes we will be using.

                     AFAttributeValueQuery avq1 = new AFAttributeValueQuery(template.AttributeTemplates["Code_point_de_réference"], searchOperator, "IR0010");

               

                     AFNamedCollectionList<AFEnumerationSet> myEnums = AFEnumerationSet.FindEnumerationSets(this.interface_PIAF.AFDB, "EnumDonneesTempsReel", AFSearchField.Name, AFSortField.Name, AFSortOrder.Ascending, 1);

                     AFEnumerationSet myEnum = myEnums.First();

                     AFEnumerationValue enumValue = myEnum.First(val => val.Name == "Indice de Wobbe");

               

                     //AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Type_de_donnée"], searchOperator, "Indice de Wobbe");//TEST 1) Type = AF Enumeration  ==> DOESN'T WORK !!!!!!

                     AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Type_de_donnée"], searchOperator, enumValue);//TEST 1.bis) Type = AF Enumeration  ==> DOESN'T WORK !!!!!!

                     //AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Publication_active"], searchOperator, true);//TEST 2) Type = Boolean ==>  WORKS !

               

                     AFAttributeValueQuery[] attributeValueQueryTable = new AFAttributeValueQuery[2] { avq1, avq2 };

               

                     AFNamedCollectionList<AFElement> myElements = AFElement.FindElementsByAttribute(elementAF_Racine, "*", attributeValueQueryTable, searchFullHierarchy, AFSortField.Name, AFSortOrder.Ascending, maxCount);

               

                     if (myElements == null)

                     {

                         break;

                     }

                     else

                     {

                         // Once the elements are loaded, we can process them.

                         this.chargerListeAvecElements(listeDonnees, myElements);

               

                         startIndex += pageSize; // Advance to next page.

                     }

              } while (startIndex < this.totalCount);

               

                          }

                          catch (ThreadAbortException ex)

                          {

                                        throw ex;

                          }

                          catch (Exception ex)

                          {

                 foundOK = false;

                 PI_MessageLogger.GetInstance().WriteException(new System.Diagnostics.StackFrame(), ex, "Une exception est survenue durant la lecture des données AF.");

              }

                • Re: FindElementsByAttribute with AFEnumeration query attribute
                  bshang

                  Are you getting the correct enumeration set? Can you share the name of myEnum and some screenshots in PSE for verify that variables match the desired objects? Otherwise, can you build a simple not-working example in PSE and share the database export XML?

                  • Re: FindElementsByAttribute with AFEnumeration query attribute
                    Rhys Kirk

                    What if you change the following part?

                     

                    AFAttributeValueQuery avq2 = new AFAttributeValueQuery(template.AttributeTemplates["Type_de_donnée"], searchOperator, enumValue.Value);
                    
                      • Re: FindElementsByAttribute with AFEnumeration query attribute
                        MaximeHT

                        Hi Rhys,

                         

                        I obtain exactly the same effect : no exception , but myElements still contains no element.

                        I think the AFAttributeValueQuery avq2  is correct, otherwise I get an exception.

                        It seems like AFElement.FindElementsByAttribute doesn't manage an AFEnumeration criteria.

                          • Re: FindElementsByAttribute with AFEnumeration query attribute
                            Rhys Kirk

                            As far as I understood the EnumerationValue is cast to an Integer anyway from the EnumerationSet when doing the comparison.

                             

                            Silly question...are you sure that from your root Element passed that you have matching Elements? Is your search operator Equals?

                            • Re: FindElementsByAttribute with AFEnumeration query attribute
                              gregor

                              Hello Maxime,

                              Can you please confirm searchFullHierarchy is of type bool and its value is true or even better replace it with true?

                              AF SDK Help says about AFAttributeValueQuery[] "An array of attribute value queries that are ANDed together to find the desired AFElement objects.

                              Please see if this works for you:

                              AFAttributeValueQuery[] attributeValueQueryTable = new AFAttributeValueQuery[1] { avq2 };
                              AFNamedCollectionList<AFElement> myElements = AFElement.FindElementsByAttribute(elementAF_Racine, "*", attributeValueQueryTable, true, AFSortField.Name, AFSortOrder.Ascending, maxCount);
                              
                                • Re: FindElementsByAttribute with AFEnumeration query attribute
                                  MaximeHT

                                  Hi Gregor,

                                   

                                  The searchFullHierarchy boolean is set to true.

                                  If I use only the AFAttributeValueQuery avq2, no elements are returned.

                                  If I use only the AFAttributeValueQuery avq1, 4 elements are returned.

                                    • Re: FindElementsByAttribute with AFEnumeration query attribute
                                      Rhys Kirk

                                      Hmmmm, is your Attribute "Type_de_donnée" using an Enumeration Set but storing its value in a PI Point?

                                        • Re: FindElementsByAttribute with AFEnumeration query attribute
                                          MaximeHT

                                          There's no PI Point tied to the Attribute "Type_de_donnée".

                                           

                                          See the AF enumeration set...

                                          PSE_Enumeration.jpg

                                          And how it is used...

                                          PSE_Element.jpg

                                            • Re: FindElementsByAttribute with AFEnumeration query attribute
                                              MaximeHT

                                              After additional test, I could obtain 4 elements in myElements by requested with "PCS" in avq2 instead of "Indice de Wobbe".

                                              When I set the default value of Type_de_donnee to "Indice de Wobbe" in the template PubTempsReel_Donnee, and  then requested with "Indice de Wobbe" in avq2, I could also obtain 4 elements in myElements.

                                              The context is :

                                              • There are 4 elements under the root element of the query
                                              • Each element as its own template that contains "Energie horaire" in PubTempsReel_Donnee_Energie_horaire, "PCS" i n PubTempsReel_Donnee_PCS, "Volume horaire" in PubTempsReel_Donnee_Volume_horaire",  or "Indice de Wobbe" in PubTempsReel_Donnee_Wobbe as default value in the attribute Type_de_donnee"
                                              • The 4 elements keep the default value of their template
                                              • The 4 templates have the same parent template PubTempsReel_Donnee

                                               

                                              My conclusion is the value red  for the 4 elements loaded (or not) is the default value of the parent template of their template.

                                              Do agrre with that?

                                               

                                              Her are some screenshots of the templates and elements:

                                              Template_Parent.jpgTemplate_Energie.jpgTemplate_PCS.jpgTemplate_Volume.jpgTemplate_Wobbe.jpgElement_Energie.jpgElement_PCS.jpgElement_Volume.jpgElement_Wobbe.jpg

                                                • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                  MaximeHT

                                                  We obtain the same behavior if Type_de_donnee is designed as a string instead of an AF enumeration.

                                                  The problem seems to be the template inheritance with an attribute overriden in child templates.

                                                    • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                      gregor

                                                      Hello Maxime,

                                                       

                                                      Are you suggesting that FindElementsByAttribute with AFAttributeValueQuery only returns correctly when the AFEnumerationValue assigned equals the one defined with the ElementTemplate?

                                                      I have tried this and cannot confirm your observation. I am running PI AF Client 2015 R2 (2.7.5.7166). I am attaching the export for the Database I've been using and paste in my sample code below.

                                                      try
                                                      {
                                                          string afServerName = "AFServer";
                                                          PISystem afSrv = new PISystems()[afServerName];
                                                          AFDatabase afDB = afSrv.Databases["Sandbox01"];
                                                          AFNamedCollectionList<AFEnumerationSet> myEnums = AFEnumerationSet.FindEnumerationSets(afDB, "Traffic Light", AFSearchField.Name, AFSortField.Name, AFSortOrder.Ascending, 1);
                                                          AFEnumerationSet myEnum = myEnums.First();
                                                          AFEnumerationValue enumValue = myEnum.First(val => val.Name == "Red");
                                                          foreach (AFElement root in afDB.Elements)
                                                          {
                                                              Console.Write("root: {0} - ", root.Name);
                                                              AFNamedCollection<AFElementTemplate> ElementTemplates = AFElementTemplate.FindElementTemplates(afDB, "traffic*", AFSearchField.Name, AFSortField.Name, AFSortOrder.Ascending, 1000);
                                                              foreach (AFElementTemplate ElementTemplate in ElementTemplates)
                                                              {
                                                                  Console.Write("{0}: ", ElementTemplate);
                                                                  AFAttributeTemplate AttributeTemplate = ElementTemplate.AttributeTemplates["Lamp"];
                                                                  AFAttributeValueQuery[] avqArray = new AFAttributeValueQuery[1] { new AFAttributeValueQuery(AttributeTemplate, OSIsoft.AF.Search.AFSearchOperator.Equal, enumValue) };
                                                                  AFNamedCollection<AFElement> myElements = AFElement.FindElementsByAttribute(root, "*", avqArray, true, AFSortField.Name, AFSortOrder.Ascending, 1000);
                                                                  Console.WriteLine("{0}", myElements.Count);
                                                              }
                                                           }
                                                      }
                                                      catch (Exception ex)
                                                      {
                                                          ConsoleColor colBuf = Console.ForegroundColor;
                                                          Console.ForegroundColor = ConsoleColor.Red;
                                                          Console.Write("Exception: ");
                                                          Console.ForegroundColor = colBuf;
                                                          Console.WriteLine(ex.Message);
                                                      }
                                                      finally
                                                      {
                                                          Console.Write("Done. Press any key to quit .. ");
                                                          Console.ReadKey();
                                                      }
                                                      
                                                        • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                          MaximeHT

                                                          Hello Gregor,

                                                           

                                                          We work with AFSDK 2.6

                                                          In order to reproduce the way we use the template inheritance, I suggest to create 3 child templates of the template TrafficLight :

                                                          • TrafficLight_Green withe the Lamp default value set to green tied to the element TrafficLight1
                                                          • TrafficLight_Orange with the Lamp default value set to Orange tied to the element TrafficLight2
                                                          • TrafficLight_Red with the Lamp default value set to Red tied to the element TrafficLight2

                                                           

                                                          Then you let the elements keeping the default value of their own template.

                                                          If I am right, you'll load the elements only if you filter with the Yellow value

                                                           

                                                          Regards

                                                            • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                              gregor

                                                              Hello Maxime,

                                                               

                                                              When creating a derived template from TrafficLight, the Lamp Attribute will become inherited. One could understand that derived templates are intended when additional properties are needed. Nonetheless, one can create an Attribute Lamp for the derived template. My understanding is that by doing so, the inherited property and its value become overwritten.

                                                              The point however is that the ElementTemplate itself is a different one (TrafficLight <-> TrafficLight_Green <-> TrafficLight_Orange <-> TrafficLight_Red). When trying to reproduce your problem, it was not clear from the code you had shared, where your ElementTemplate reference came from.

                                                              I asked a colleague of mine to share an eye and he suggested trying the Element Search in PI System Explorer since what works there "usually" should be doable programmatically too. This dialog as well shows there now exist 4 different Element Templates.

                                                              Can you please see if you can reproduce your issue within PSE?

                                                              While I usually come from the code perspective, the colleague that I engaged looks from a different angle. When looking at the information you posted it's not clear what you are trying to accomplish. It may make sense to take a step backwards and try to understand what you are trying to accomplish.

                                                               

                                                              In case you suspect a bug, it should be reproducible in the current version because there's not much value in reporting a bug that only exists in older versions.

                                                                • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                                  MaximeHT

                                                                  Hello Gregor,

                                                                   

                                                                  I confirm that the property Type_de_donne is overwritten in the child template.

                                                                  In the code I shared, the template is the parent one = PubTempsReelDonnee.

                                                                  Her some screenshots showing the elements with their template:

                                                                  Element_Energie_Gen.jpgElement_Wobbe_Gen.jpgElement_Volume_Gen.jpgElement_PCS_Gen.jpg

                                                                   

                                                                  In PSE, requesting with Type_de_donnee = "PCS" (parent template default value), we obtain 4 elements:

                                                                  PSE_PCS.jpg

                                                                  In PSE, requesting with Type_de_donnee = "Indice de Wobbe" (only one template default value), we obtain 0 element:

                                                                  PSE_Wobbe.jpg

                                                                    • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                                      gregor

                                                                      Hello Maxime,

                                                                       

                                                                      looks like we have made some progress in understanding what the issue is about.

                                                                       

                                                                      I recognize that your searches have the template set to PubTempsReel_Donnee but the other screenshots indicate that you are not using this Template but the ones you derived from it. I am uncertain if referencing another template than the one used for object creation in the search is appropriate. What do you think?

                                                                       

                                                                      I am also wondering if what you are trying to accomplish wouldn't work more natural using a different approach. You haven't yet shared much information about what you like to accomplish. Have you considered using e.g. Element Categories?

                                                                       

                                                                      The names that you use within the Element Hierarchy indicate the hierarchy doesn't reflect any asset hierarchy but is a kind of data or report management system. There's nothing wrong with that but please keep in mind what Asset Framework is designed for.

                                                                       

                                                                      In case the experienced behavior is not inline with your expectations, I would conclude that you suspect a bug and we should involve development to at least get their judgment. It would however be helpful to know what behavior you expect.

                                                                        • Re: FindElementsByAttribute with AFEnumeration query attribute
                                                                          MaximeHT

                                                                          Gregor,

                                                                           

                                                                          The goal of the module we are coding is to update elements that implement one of the four templates that inherits from PubTempsReel_Donnee.

                                                                          An entry (CSV) file is loaded and gives the description of the elements that have to be updated.

                                                                          In the file:

                                                                          • 1rst column contains the Code_point_de_reference of the element
                                                                          • 2nd column contains the Type_de_donnee of the element
                                                                          • 3rd column contains the name of the attribute to update
                                                                          • 4th column contains the new value of the attribute to update

                                                                          For each line, the element should be loaded using the two filters in the query = Code_point_de_reference + Type_de_donnee

                                                                          The AFElement.FindElementsByAttribute function seemed to be the best way to retrieve an element with attributes criteria.

                                                                          But the Type_de_donnee value is compared with the default value of the common template (that is used to build the query) instead of comparing with the element attribute value.

                                                                          Is it a bug or a misunderstanding about the use of the AFElement.FindElementsByAttribute function?

                                                                          The AFSDK Reference describes the function as "Performs a search on the element's name and attribute value within AFDatabase...".

                                                                          So, I'm interested in the judment of the development team.