Convert Structure list to record list?

Convert Structure list to record list?

  

I have an integration function that takes a Record List of type Text as input.

When I try to pass it a List of Text structures in Service Studio 10 I get the error:
"Expected Text Record instead of Text."

How do I create a list of Text-structure Records to pass to my function?

You can create a Text List or a Text Record List. Instead of passing a "Text List" try to pass a "Text Record List", maybe that's the issue?

I don't know what is the difference between "List" and "Record List", seems the same thing

Here are the relevent parts:

In Integration Studio:

This is the variable definition:


And this is the expression and error message:

Oh!  YOu were right!

I had the variable defined as List of Text,  changing it to List of Record(Text) fixed it!

Thanks, this had me badly stalled.

Nice to know that was enough to solve it.

I don't know what's the difference between "List of" and "List of Record", seems to be the same thing. Can someone explain the difference?

As I understand it, List of <structure>  is a list of structures, which are temporary in memory things.
List of <record> <structure> is a list of records whose fields match those of the given structure.

The Structure/Record thing IS an odd distinction I'm still trying to wrap my head fully around.

Solution

I'll try to shine some light on the difference between Record Lists and Lists. In the olden days, before version 9, there were only Record Lists. A Record List is a list or Records. You can think of a Record as a container of one or more Structures or Entity Records (yeah, en Entity Record is actually not a Record). Typically, if you have a query (SQL or Aggregate), you'll output multiple Entity Records. These are grouped together in a Record. So the output of a query is always a Record List.

The downside of a Record or Record List is that you'll always have to name both the Record name and the Structure or Entity name if you want to reference an attribute. Say you have a Record variable with name MyData, containing a single structure called MyStruct with an attribute called MyValue, you need to type MyData.MyStruct.MyValue. This makes sense if the same Record also contains a structure called MyStruct2, so you can also say MyData.MyStruct2.MyOtherValue for example. But if there's only a single structure, having to type MyStruct every time is laborious. With Record Lists, the path gets even longer: MyDataList.Current.MyStruct.MyValue.

Secondly, the Records of old could only contain Structures, Entity Records and/or other Records. Not "simple types" like Text, Integer or Decimal. So if you needed a list of integers, you needed to create a structure with a single, integer, attribute, to be able to do that.

Starting with version 9, this all changed with the introduction of "simple" Lists or just Lists. These Lists can contain Structures, Entity Records and simple types directly, without wrapping them in a Record or, in case of simple types, also first in a structure. This also makes it easier referencing the attibutes: in the example above, having a Record of MyStruct, you can reference MyValue simply with MyData.MyValue (or MyDataList.Current.MyValue in case of a List). For lists of simple types, MyList.Current yields the value (instead of the MyList.Current.MyIntegerStruct.Value of old).

Now, in Service Studio, dealing with Record Lists and Lists is made pretty transparent. When assigining, or when passing as parameter, Lists are converted to Record Lists and back when needed (and vice versa). It's still good to make sure you only need Record Lists when really needed, because conversion gives overhead, especially with long lists. Also note that conversion is not available when calling a Function from an expression.

For extensions, dealing with Record Lists has a specific API available. In fact, Integration Studio doesn't even know Lists of simple types, only Record Lists. Some extensions, like XMLRecords or SortRecordList deal with generic Record Lists, i.e. the Structure is not defined in the extension itself. They typically use reflection to find out what the structure of the Records are. Dealing with Lists this way is far from trivial (the elements have a different internal structure), so not all extensions are reworked to support this.

I hope this clarifies it a bit. If not, let me know.






Solution

What is the equivalent of ListAppend in a For Loop?

I have an entity record list from an Attribute/ Query and want to append values returned a list for all records returned by the query.

Since I cannot use ListAppend in a For Loop, how can I do this?

I need this as I'm trying to create a timeline of event dates.

Your help will be appreciated.

Seth wrote:

What is the equivalent of ListAppend in a For Loop?

I have an entity record list from an Attribute/ Query and want to append values returned a list for all records returned by the query.

Since I cannot use ListAppend in a For Loop, how can I do this?

I need this as I'm trying to create a timeline of event dates.

Your help will be appreciated.

Hi Seth,

You have the option to use ListAppendAll, when not iterating over the list, or ListAppend if you are looping over the list.

I'm not sure if I am understanding your problem clearly. Why can you not use ListAppend in a for loop?

Let me know,

Justin


Hi Seth,

Apparently, you are confusing two things. When iterating over a List, you cannot modify that list, i.e. you can't ListAppend(All) to it, you can't ListDelete or ListInsert it etc. But it is perfectly possible to use those actions on another list, one that is not iterated over.

Note that if you are on P10 (i.e. version 10 of the Platform), there's a whole bunch of new List actions that you can use to create a new list from a list without iterating over it.

Thank you Justin and Kilian for your assistance.

I refrained from using ListAppend in the For Loop as I read from OutSystems online Learning material found below that you cannot use ListAppend in a For Loop.

http://www.outsystems.com/help/servicestudio/9.1/index.htm#t=Language_Reference%2FSystem_Actions_and_Functions%2FListAppend_Action.htm

I listened to you and decided to use it as advised and it worked. I guess Outsystems needs to update the online learning material's Remarks as shown above.

Much appreciated

Hi Seth,

I agree the help file is not very clear, but it says whay I also said: you can't use a ListAppend on a list being iterated over. The litteral text is:

"You cannot execute this action when you are managing a List inside a For Each loop."

"managing a List" is indeed very unclear language, and it also omits that you can't Append to the "managed" list, but you can to other lists. So that's the rule: no changing a list that's used in the For Each, but you can ListAppend to other lists*.

*Note that if you assign a List variable to another List, both point to the same list. Use ListDuplicate if you really need a copy.

Folks,


I'm back again wanting to know the correct use of ListAppend.


See the attached picture for the logic I'm trying to execute. Whjat I did is the following:

1. I created an SQL query to return values I can use as datapoints to display on my donut-graph/ chart.

2. I then created a For Loop so I can assign values returned from the SQL query to a record variable (VarDataPoint) of DataPoint Type

3. I them used ListAppend to append that record to a list of data points (VarDataPointList) of Data Type "DataPoint List".

Now, when I run a debug to see what's going on, the first 2 steps above run correctly. i.e., I can see the data being written to the record correctly, but when I run step 3 to append that record to a list, then ListAppend does not seem to be writing anything to the DataPoint List. It remains blank.

What am I doing wrong?

Thanks,

Seth

Hi Seth,

Two things:

1) Without also seeing the logica of the ListAppend, it's difficult to see where it's going wrong. However, keep in mind that the debugger is known to occasionally not show the correct information (especially with lists), so that might be it (unless of course you actually don't get any output). If you can attach the eSpace OML I can take a closer look.

2) Starting with Platform 10, you usually do not need a ForEach/ListAppend, but you can do a ListAppendAll, with destination VarDataPointList and source the output of the query. Service Studio then asks you to supply a mapping, which are basically assignments like in your assignment statement.

Kilian Hekhuis wrote:

Hi Seth,

Two things:

1) Without also seeing the logica of the ListAppend, it's difficult to see where it's going wrong. However, keep in mind that the debugger is known to occasionally not show the correct information (especially with lists), so that might be it (unless of course you actually don't get any output). If you can attach the eSpace OML I can take a closer look.

2) Starting with Platform 10, you usually do not need a ForEach/ListAppend, but you can do a ListAppendAll, with destination VarDataPointList and source the output of the query. Service Studio then asks you to supply a mapping, which are basically assignments like in your assignment statement.

Dear Kilian


Thank you for getting back to me. I have created a sample OML with the ListAppend logic I am trying to execute in the attached OML.


I am aware that I could have directly assigned the SQL list to the graph but that would have meant that my chart label would be the Static Category Table Id instead of the corresponding category Id's label. Had I wanted to directly assign the SQL list to the Chart, I would have had to modify my structure to add one extra column called "Label" and ensure I select the label also in the SQL. But I did not want to modify the structure but go the List Append route. That way, I was also creating possibilities for future manipulation of SQL list before charting it.

In your reply, could you please share different options I could have pursued to achieve the same goal?


I look forward to hearing further from you.

Kind regards,

Seth

Hi Seth,

A few remarks about your code:

1) You have a ListClear of the output list. This is not needed, as all parameters and variables are guaranteed to be initialized to their default values, which for a list means it's already empty.

2) You use a SQL instead of an Aggregate, while the SQL contains only simple joins. The general advise is: don't do that. If you can avoid SQL, do so. The Platform can perform many checks and do optimizations on Aggregates, but it can't as well for SQL.

3) You use a SUM() instead of a COUNT() for the Category count. That's not gonna work :).

4) In the Assign, you have a GetBenefitsCategories(). This isn't necessary, since you already join the BenefitCategories in your query. If you put a Group By on the Label, you can directly use it, which saves you a lot of queries (each Get Action from an Entity is a query).

5) You mistunderstood me with regards to the direct assignment of the list. I didn't mean that the SQL should output directly to a DataPoint (which is a possibility, but I wouldn't use a SQL anyway), but that you should map in the ListAppendAll.

I have attached your eSpace, with (solely for the DataActionCheckPortfolio Action) the fixes that I would recommend.

Kilian Hekhuis wrote:

Hi Seth,

A few remarks about your code:

1) You have a ListClear of the output list. This is not needed, as all parameters and variables are guaranteed to be initialized to their default values, which for a list means it's already empty.

2) You use a SQL instead of an Aggregate, while the SQL contains only simple joins. The general advise is: don't do that. If you can avoid SQL, do so. The Platform can perform many checks and do optimizations on Aggregates, but it can't as well for SQL.

3) You use a SUM() instead of a COUNT() for the Category count. That's not gonna work :).

4) In the Assign, you have a GetBenefitsCategories(). This isn't necessary, since you already join the BenefitCategories in your query. If you put a Group By on the Label, you can directly use it, which saves you a lot of queries (each Get Action from an Entity is a query).

5) You mistunderstood me with regards to the direct assignment of the list. I didn't mean that the SQL should output directly to a DataPoint (which is a possibility, but I wouldn't use a SQL anyway), but that you should map in the ListAppendAll.

I have attached your eSpace, with (solely for the DataActionCheckPortfolio Action) the fixes that I would recommend.

Thank you very much. Apart from my silly mistake of using Sum instead of Count, your rendition is quite sleek and neat! I guess I need mroe training on the use of Aggregates because I wasn't sure I could manipulate them to that extent.


Thank you very much. Be well


Hi Seth,

Glad I could be of help, and glad you liked it. Aggregates are pretty neat, and unless you need e.g. subqueries, you can use them for almost everything you can use SQL for. Good luck with your further endeavours :).

Seth wrote:

Folks,


I'm back again wanting to know the correct use of ListAppend.


See the attached picture for the logic I'm trying to execute. Whjat I did is the following:

1. I created an SQL query to return values I can use as datapoints to display on my donut-graph/ chart.

2. I then created a For Loop so I can assign values returned from the SQL query to a record variable (VarDataPoint) of DataPoint Type

3. I them used ListAppend to append that record to a list of data points (VarDataPointList) of Data Type "DataPoint List".

Now, when I run a debug to see what's going on, the first 2 steps above run correctly. i.e., I can see the data being written to the record correctly, but when I run step 3 to append that record to a list, then ListAppend does not seem to be writing anything to the DataPoint List. It remains blank.

What am I doing wrong?

Thanks,

Seth

Hi,

One thing I will do differently, trying to put data point stucture as output of advanced query to avoid loop.

Nelson,

I disagree with you very much! Have you even seen my post? The loop isn't needed at all! A ListAppendAll will do.

1) Don't use SQL unless really needed;

2) Avoid business rules or setting constant data in SQL, for maintainabilities sake!

Kilian Hekhuis wrote:

Nelson,

I disagree with you very much! Have you even seen my post? The loop isn't needed at all! A ListAppendAll will do.

1) Don't use SQL unless really needed;

2) Avoid business rules or setting constant data in SQL, for maintainabilities sake!

Since I no longer need SQL, I guess I can also do away with the kind of method I used to fetch data by using the aggregate directly and mapping its results directly to the chart. That way I suppose I'll then do away with the need for ListAppendAll.


Thoughts?


I must say your method helped me understand how to use ListAppendAll correctly without the need for the Loop.


Much appreciated  

 


Hi Seth,

The only reason to avoid doing the mapping in the chart itself, would be to avoid putting business rules (like calculations) in the screen itself. If you don't have any, yes, you could do that directly.

EDIT: Speaking of which, instead of a ListAppendAll you could also just use an assign in the example I gave:

Thanks. For now, I'll leave it as you've done it to make room for possible future business rules changes and need for calculations.


Thanks

Kilian Hekhuis wrote:

Hi Seth,

The only reason to avoid doing the mapping in the chart itself, would be to avoid putting business rules (like calculations) in the screen itself. If you don't have any, yes, you could do that directly.

EDIT: Speaking of which, instead of a ListAppendAll you could also just use an assign in the example I gave:

Like good wine, the solution is getting better and better with time ;-)