Concat many records in 1 record

Hi,
  How to concat many records in 1 record, for instance, in a Master-Detail1-Detail2-Detail3, Detail3 is concat in one field of Detail3.
   TMonument = Class
    public
      Name: String;
   end;
   TCity = Class
   public
     Name: String;
     MonumentList: TList<TMonument>;
   end;
   TDistrict = Class
   public
     Name: String;
     CityList: TList<TCity>
   end;
   TCountry = class
   public
     Name: string;
     DistrictList: TList<TDistrict>;
  end;

  Result:    
  Country: Portugual(Master)
       District: Lisbon(Detail1)
              City: Lisbon(Detail2)
                 Monument: Torre de belem (Detail3)
                 Monument: castelo de S?o Jorge (Detail3)
                 Monument: Mosteiro dos Jeronimos(Detail3)
       District: Porto(Detail1)
              City: Porto(Detail2)
                 Monument: Torre do clerigos (Detail3)

                 Monument: port wine cellars (Detail3)

  Required Result:
  Country: Portugual(Master)
       District: Lisbon(Detail1)
              City: Lisbon(Detail2)
                 Monument: Torre de belem, Castelo de S?o Jorge, Mosteiro dos Jeronimos (Detail3)
       District: Porto(Detail1)
              City: Porto(Detail2)
                 Monument: Torre do clerigos, port wine cellars (Detail3)
 
 Thanks

Hi,


You can use the "<#List>" tag to do this. I'll quote the docs just in case:



List		
	Syntax:	
		<#List(dataset name and column)>
		or
		<#List(dataset name; list separator; agg expression; filter)>
	Parameters:	
		dataset name (and column): Name of the dataset in which we want to get the values as a list. Note that this dataset doesn't need to be inside any named range, since we will use all of its records anyway. If "agg expression" is present, you don't need to include the column name, as the columns to aggregate will be taken from the expression. If not present, you need to include the column in which you want to aggregate.
		list separator: This parameter is optional. If not present it will default to a single space. This is the character that will separate the elements in the list. Note that if you want to us a semicolon here (;) you will have to write it in quotes (";") so it is not considered a parameter separator 
		agg expression: This parameter is optional. An expression that will be applied to every record in the dataset.(any excel function is valid here, and you can use any combination of Excel functions) Null values will be ignored and not added to the list. If not present, the values of the column specified in "dataset name and column" will be used 
		filter: This parameter is optional. If present, it should be an expression that returns true or false. Again, any excel formula is valid here. Only those records where the filter value is true will be used in the aggregate.
	Description:	
		Returns a string with all the values of a table one after the other, and separated by a delimiter. If the table has only one record, you can use <#List(table.field)> to get the value of the only record without having to define any "__table__ named range.
	Examples:	
		<#List(Employees.Lastname)> will return a string like "Smith Brown Perez".  As we didn't specify a separator, a single space will be used. If you know Employees has only one record, you could have used this to avoid defining a "__employees__" named range.
		<#list(employees.lastname;, )> will return a string like "Smith, Brown, Perez". 
		<#list(employees;"; "; <#employees.firstname> & " " & <#employees.lastname>)> will return a string like "John Smith; Carl Brown; Jorge Perez".  Note that as we wanted to use ";" as list separator, we had to write it inside quotes.




In your case, you should write something like: <#list(MonumentList;, ;<#MonumentList.Name>)>
And remember that if you use a <#List>, you don't need to put the tags inside a __MonumentList__ range. As List will use all the record in the database and concatenate them, it doesn't need a named range to fill different records in different cells. In fact, you should remove the __MonumentList__ Named range, because if you don't, you will get:

 Country: Portugual(Master)
       District: Lisbon(Detail1)
              City: Lisbon(Detail2)
                 Monument: Torre de belem, Castelo de S?o Jorge, Mosteiro dos Jeronimos (Detail3)
                 Monument: Torre de belem, Castelo de S?o Jorge, Mosteiro dos Jeronimos (Detail3)
                 Monument: Torre de belem, Castelo de S?o Jorge, Mosteiro dos Jeronimos (Detail3)
                 (repeated for every record in __MonumentList__)
       District: Porto(Detail1)

 

A last hint about <#List>: You can use the fact that it doesn't need a named range to output databases that you know have exactly one record without needing to define a named range for them.


Hi,
  Sorry, I can not make it work, is there a demo about that? is there on documentation?
  thanks

Hi,
The documentation is in FlexCelTags.xls (in the Documentation folder of the FlexCel installation), but it says what I quoted in my last post. And there is really not much more to say about <#list()>, it just takes all the records in a dataset and outputs them all in one line separated by some separator.

So if you have a dataset/list with 3 records:
Torre de belem
Castelo de S?o Jorge
Mosteiro dos Jeronimos 

<#List> will return:
Torre de belem, Castelo de S?o Jorge, Mosteiro dos Jeronimos 

That is all there is to it. Now, looking at your example I think I can figure out why it is not working for you. What I noticed is that List will work only in datasets you add with AddTable, (In this case it would be "Country"), not with datasets that are a property of the master table (like City) in your case.

So we are adding a fix here to allow List to also work in detail datasets. It should be available in the next bugfix release, which should be coming by the end of this week, start of the next.
Adrian Gallero2015-11-17 11:18:44

Hi,
  Ok, thanks.

Hi,
  New Release available. This issue is solved?
thanks

Hi,
Sadly we didn't got time to make it for 6.7.1.  It was more complex than what I expected, and we will have to take some time to see how to fix it without breaking existing functionality. But in your case, you have a simple workaround:

Add a member in the class:

TCity = Class
   public
     Name: String;
     MonumentList: TList<TMonument>;
     function AllMonuments: string;
   end;
   
   
...
function TCity.AllMonuments: string;
begin
  Result := ContatenateAllMonumentsInASingleString;
end;


And then in the template, don't defing a __monuments__ range. Just write <#city.AllMonuments> inside the __city__ range

Hi,
  Can not add "function AllMonuments: string;" to TCity. Classes are created by DataModeler with export to Aurelius option, so every change to to database schema , i have to add AllMonuments manually to TCity.
   Any other sugestion?
  Thanks

ok, if you can't add functions to TCity, then the only solution I can think will be to wait until we add support for this. I think it can be added this week, I'll let you know. The other solution I can think would be to use a class helper, but RTTI won't find methods in class helpers.

I will wait,

Thank you so much

Hi,
Just to let you know this has been fixed internally. We still need to run more tests and add a couple of unrelated features, but 6.7.2 should be released this week and it will contain this fix.

Hi,
Finally 6.7.2 is out and it should fix this. Sorry about the delays.

Hi, Adrian
  After install V6.7.2,  works as expected.
  Thanks