Subrelatorio jasper com um JRMapCollectionDataSource. Esse Collection só é percorrido uma vez

Olá pessoal, seguinte…
Tenho um relatorio master e um subrelatorio, que naturalemente deve ser chamado a cada iteracao do relatorio master…
Tanto o relatorio como o subrelatorio utilizam uma JRMapCollectionDataSource, mas a Data Source do subrelatorio é percorrida somente uma vez, ou seja, somente pra primeira iteracao do relatorio master. Acredito que é pq essa Data Source chega ao seu fim, ou seja, atinge a sua última posição… e a partir da segunda iteracao do rel master, nao se percorre mais essa Data Source e aparece vazio as informacoes.
Por exemplo:

Collection rel master: O codigo é a chave do map, e a descrição é o valor (lembrando que cada posicao dessa collection é um HashMap com esses valores…) Com essa Collection cria-se a JRMapCollectionDataSource(Collection) do rel master.
codigo----descricao
1-----------des 1
2-----------des 2
3-----------des 3

Collection subrel : Com essa Collection cria-se a JRMapCollectionDataSource(Collection) do subrelatório.
codigo----descricao
1-----------dessub 1
2-----------dessub 2
3-----------dessub 3

Quando executa aparece assim:

rel:
1-----------des 1

----subrel:
----1-----------dessub 1
----2-----------dessub 2
----3-----------dessub 3

rel:
2-----------des 2

rel:
3-----------des 3

ou seja, só percorre a Data Source do subrel pra primeira iteracao do relatório… entao, após cada iteracao do rel deve-se voltar pra posicao inicial a DataSource do subrel… mas como se faz isso?
A classe JRMapCollectionDataSource implementa a interface JRRewindableDataSource, que tem um método moveFirst() que faz isso,
mas como chamá-lo após cada iteração do rel? Como colocar isso no ireport??

Grato…

Olá amigo!!

Provavelmente você deve estar usando a seguinte estrutura.

Class RelaMaster () {
String cod;
String des;
Collection SubRelatorio;
....
gets 
sets

}

Class SubRelatorio () {
String cod;
String des;
}

No caso, vc deve estar populando o relatorio principal e colocando varios objetos do subRelatorio na colecao que ele possui.

Entao no seu relatorio, vc conterá o relatorio principal com as variavies do relatorio principal e tb uma collection que deve ser declarada no jasper como “java.util.Collection”.

Certo agora vc deve adicionar um subRelatorio ao relatórioPrincipal.
Na propiedade do SubRelatório, existe a aba “SubRelatorio”, la existe um combo com a opção “usar um datasource”, la vc indica sua colecao declarada, por exemplo:
new JRBeanCollectionDataSource($F{subRelatorio}).

E no subRelatorio, coloca as variasveis da classe SubRelatorio.

Assim deve funcionar.

// Agora se você possui uma colecao de maps, acredito que usando o JRMapCollectionDataSource no lugar de JRBeanCollectionDataSource deve funcionar.

Qualquer dúvida so falar, ou se quiser me add no msn ae rdmardegam@hotmail.com. Ou se funcionar, posta dizendo aee

Abraço.

Olá amigo, muito obrigado pela ajuda.

Eh, a sua idéia vai funcionar, pois eu já fiz um rel com subrel dessa forma, passando uma collection pro rel, e criando uma JRBeanCollectionDataSource pra cada vez que se chama o subrel:

new JRBeanCollectionDataSource($F{subRelatorio}).

Porém, o que eu estou querendo contonar é isso, ou seja, criar um novo objeto idêntico ao que já existe pra cada iteração do relatorio, com um new JRBeanCollectionDataSource($F{subRelatorio}). Pra que fazer isso sendo que pode-se usar o mesmo objeto? Somente pra gastar memória e colocar o garbage colector pra ter que trabalhar mais. Imagine um relatorio com 1000 registros, vc teria 1000 objetos idênticos na memória…

Pra não ter que fazer isso, tem que retornar o DataSource a posição inicial após cada iteração do relatorio.
O método moveFirst() da interface JRRewindableDataSource retorna o DataSource a posição inicial, porém não sei como(onde) usá-lo no ireport.
Note que a classe JRBeanCollectionDataSource também implementa essa interface, portanto também funcionaria pra ela.

Grato.

Amigo, pelo que entendi.

Então você vai ter apenas 1 relatorio principal com valores diferentes!

E o Sub sempre vai ser o mesmo é isso ??

Me add no msn para conversarmos melhor ? rdmardegam@hotmail.com

Se for isso q estou pensando !!

Voce pode simplesmente fazer uma colecao do relatorio principal e passar como JRBeanCollectionDataSource;

Ae vc cria uma unica colecao dos subrelatorio e adiciona esse colecao no Map dos relatorios.

No jasper ao recupera o parameters como JRBeanCollectionDataSource.

Entao, vc so vai ter uma instancia da colecao do subrelatorio sempre se repetindo a cada looping do primeiro relatorio.

Eh, eu não entendi o que vc quis dizer com ter apenas 1 relatório principal com valores diferentes… e o sub nao vai ser sempre o mesmo, ele vai ser gerado sempre pela mesma dataSource, ou seja, sempre pelo mesmo objeto…

Eu pretendo usar da forma que se usa um relatorio com subrelatorio, ou seja, se tem um relatório e pra cada informacao desse relatorio se chama um subrelatorio, que naturalmente é referente as informações do relatório…

Grato.

Olá amigo, é nao entendi muito bem ainda oq vc quer, mas td bem.

N vejo problema em instanciar sempre uma JRBeanCollectionDataSource().
Ja fiz relatorios significativamente grandes e nunca deu problema.

Se puder postar o codigo e os fontos do que vc esta tantando fazer para que talvez possa ajudar mais.

Abraço.

Olá amigo, axo que não adiantaria postar o código, pois o que estou querendo resolver e a respeito da execução do relatório, e não a respeito de código java. Mas vou explicar agora e axo que vc vai entender…

Imagine que se tenha varios produtos e várias compras desses produtos armazenadas no banco, e se quer gerar um relatório que mostra todas as compras de produto, mas separadas por produto . Tudo bem, é só fazer um relatório que busca todos os produtos, e um subrelatório que mostra as compras de acordo com cada produto do relatório.
Pra fazer isso usando JRBeanCollectionDataSource, é só criar uma Collection de beans de produtos com todos os produtos, e outra com todas compras de todos os produtos, com beans de todas as compras pra ser mais claro, após isso criar uma JRBeanCollectionDataSource passando a Collection de produtos:

new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(produtos), e passar a Collection de compras de produtos como parametro para o rel, com o parametro do tipo Collection como vc sugeriu. E após isso mandar gerar o relatório. Logicamente, tudo isso em código Java.

Na criação do rel se colocaria o relatorio para percorrer o JRBeanCollectionDataSource de produtos e criaria um subrelatório na banda detail, ou seja, pra cada produto se chama esse subrelatorio e imprime as compras dele.

Então, onde se especifica o DataSource do subrelatorio, se coloca o DataSource de compras, como voce sugeriu: new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(compras).

Ok, vai funcionar… E visualmente não vai se ver problema, como você não viu. Na verdade a questão que estou querendo resolver é em questão de desempenho.

Mas você percebeu que criou um objeto net.sf.jasperreports.engine.data.JRBeanCollectionDataSource idêntico para cada produto do relatorio? Cada vez que se chama o subrelatorio se cria o net.sf.jasperreports.engine.data.JRBeanCollectionDataSource passando a Collection de compras, mas a Collection de compras não é sempre a mesma? Então eu posso usar somente uma net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(compras) pra todos os subrelatorios…

Imagine se tiver 1000 produtos, 1000 objetos idênticos na memória… E se gerar esse relatório 3 vezes seguidas? 3000… haja memória e serviço pro garbage collector.

Mas se ao invés de eu passar new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(compras) pro subrelatorio, eu criar essa DataSource no codigo java e passar ela como parametro pro
relatorio (tem que ser do tipo Object), e pro subrelatorio eu já passar a DataSource direto, ou seja, a mesma DataSource (objeto) com todas as compras pra todos os subrelatorios.
Acontece que só percorre essa DataSource pro primeiro produto, pq essa DataSource chega ao fim, e a partir do segundo produto nao mostra mais as compras, pq a DataSource está na sua última posição, pq está usando O MESMO objeto e não criando um novo pra cada subrelatório…

Solução: Voltar a DataSource a posição inicial após a chamada a cada subrelatório… O que estou querendo aprender a fazer é isso.
Como eu já disse a classe net.sf.jasperreports.engine.data.JRBeanCollectionDataSource implementa a Interface net.sf.jasperreports.engine.JRRewindableDataSource que tem um método moveFirst(),
que faz isso : “Moves back to the first element in the data source”.

A questão é, como chamar esse método após a chamada ou execução de cada subrelatório? Como colocar isso no Ireport?

Axo que agora vc deve ter entendido…

Grato.

E ai galera, ninguem tem nenhuma idéia? as minhas já se esgotaram…

Grato.

tenta usar list no lugar de subrelatorio :idea: