Duvidas sobre o MentaBean (BeanConfig)

Tenho duas duvidas sobre o MentaBean:

1-> Por exemplo voce tem uma entidade Pessoa e dentro da entidade Pessoa voce tem uma entidade Endereço que possui dentro delas as entidades Rua, Cidade, Cep etc… Como mapear isso no MentaBean? Teria que incluir a parte do Endereco depois de incluir a Pessoa, utilizando dois BeanConfig ou via sql puro mesmo?

Exemplo de como fica a estrutura da classe:

Pessoa
Endereco
Rua <-Também é uma Entidade

2->Aqui nos temos a entidade Pessoa com os atributos genericos da Pessoa (nome, codigo,telefone …) e temos as entidades Pessoa Fisica e Pessoa Juridica que herdam da entidade pessoa e acrescentam alguns campos específicos… Como ficaria essa situação no MentaBean já que os dados são todos gravados na mesma tabela mas no mapeamento não tem como eu dizer que os dados devem ser pegos de outra classe…

[quote=Jose111]Tenho duas duvidas sobre o MentaBean:

1-> Por exemplo voce tem uma entidade Pessoa e dentro da entidade Pessoa voce tem uma entidade Endereço que possui dentro delas as entidades Rua, Cidade, Cep etc… Como mapear isso no MentaBean? Teria que incluir a parte do Endereco depois de incluir a Pessoa, utilizando dois BeanConfig ou via sql puro mesmo?

Exemplo de como fica a estrutura da classe:

Pessoa
Endereco
Rua <-Também é uma Entidade

[/quote]

A filosofia do MentaBean é não introduzir NENHUM tipo de mágica. Para tal já tem o Hibernate com a sua magia negra.

A BeanSession tem duas funções principais: 1) Fazer CRUD de um Objeto (um APENAS). 2) Te ajudar a construir as queries, abstraindo e automizando o trabalho sujo do JDBC.

Para tal a BeanSession usa o BeanConfig para saber o mapeamento dos campos do objeto para a tabela no banco.

Sabendo disso então vc terá DOIS BeanConfigs, um para cada objeto. Daí se um contém o outro, vc que decide se vai fazer isso numa query só com join OU se vc vai fazer isso com duas queries, usando os métodos CRUD da BeanSession.

Simples. Cria dois BeanConfigs diferentes configurados para a mesma tabela. Um para cada objeto. :wink:

Mas se eu criar dois BeanConfig um para a entidade Pessoa e um para a entidade Endereço eu teria um Insert e um Update no banco somente para gravar o mesmo objeto já que essas informações são gravadas na mesma tabela

O mesmo caso ocorre na segunda situação porque os dados de Pessoa Física e Pessoa Jurídica também são gravados na mesma tabela…

O MentaBean poderia fazer alguma rotina que permiti-se pegar os atributos que estão dentro de outro objeto

Essa situação não seria muito rotineira para ganhar um pouco mais de atenção do MentaBean?

[quote=Jose111]Mas se eu criar dois BeanConfig um para a entidade Pessoa e um para a entidade Endereço eu teria um Insert e um Update no banco somente para gravar o mesmo objeto já que essas informações são gravadas na mesma tabela

O mesmo caso ocorre na segunda situação porque os dados de Pessoa Física e Pessoa Jurídica também são gravados na mesma tabela…

O MentaBean poderia fazer alguma rotina que permiti-se pegar os atributos que estão dentro de outro objeto

Essa situação não seria muito rotineira para ganhar um pouco mais de atenção do MentaBean? [/quote]

Não entendi o que vc quer fazer. Vai ter que desenhar. :slight_smile:

O MentaBean por filosofia não tenta adivinhar nada. Vc faz o que quiser e ele te ajuda com CRUD e JDBC.

O mapeamento abastrai tudo então se amanhã vc adiciona um novo campo no seu objeto (e por conseguinte na tabela) vc só adiciona uma linha na configuracao programatica, sem precisar mudar nenhuma query.

Explica o que vc quer fazer com código para ver se eu entendo.

Lembrando tb que por ser open-source, nada te impede de baixar o código e fazer um patch. Se fizer isso submete o patch para a avalicação da comunidade.

A minha ideia é facilitar a gravação de atributos que não estão na classe que esta configurado o BeanConfig…

Tive essa ideia aqui:

public class TesteReflection {
	public static void main(String[] args) {
		//Na classe BeanConfig o metodo 'field' no primeiro parametro poderia aceitar uma informaçao assim:  
		//atributo.atributoDoMeuAtributo.atributoDoMeuAtributoDoMeuAtributo.Etc...
		//Exemplo: A classe passada para o BeanConfig foi a classe Pessoa 
		//dentro dela tem o atributo cidade que é uma outra entidade
		//Vc quer gravar no banco é o id da cidade então vc poderia passar para o BeanConfig.field como primeiro parametro
		//uma String assim "cidade.id" e ele por refletion busca-se aquele valor dentro do objeto Pessoa
		//Abaixo tem um exemplo de como ficaria o código
		
		String[] v = "cidade.id".split("[.]");//aqui seria o parametro recebido pelo metodo
		String classe= Pessoa.class.getName();//aqui é a classe ja configurada no beanConfig
		Field fld = null;
		for(int i=0; i<v.length;i++){
			fld=getAtributo(classe,v[i]);
			classe=fld.getType().getName();
		}
		System.out.println(fld); // aqui ele teria encontrado o atributo e então poderia ser pego o seu valor
	}
	
	public static Field getAtributo(String classe, String atributo){
		try{
			Class cls = Class.forName(classe);  
			Field fieldlist[] = cls.getDeclaredFields();  
			for (int i = 0; i < fieldlist.length; i++) {  
				Field fld = fieldlist[i];  
				if(fld.getName().equals(atributo)){
					return fld;
				}
			}  
		}  
		catch (Throwable e) {  
			e.printStackTrace();
		}
		return null;
	}
	
}

O problema ta na busca… teria que marcar o campo como write-only :slight_smile:

Agora sim, desenhando com código até uma hiena como eu entende.

A sua idéia é válida sim, mas há uma maneira que eu uso para resolver isso que funciona muito bem também, principalmente quando vc quer ou precisa fazer lazy loading:

Pessoa CONTEM Cidade


public class Pessoa {

   private String nome;
   private int cidadeId; /// &lt;======================= !!!!
   private Cidade cidade;

   // ...
}

Então vc coloca no BeanConfig APENAS o campo cidadeId que é o campo que precisa ser gravado na tabela anyways. Logo quando vc carrega o Pessoa ela vem sem a cidade mas com o id da cidade. Daí a qualquer momento você pode pegar o ID da cidade, carregar ela (ou pegar de um cache ou lista estática) e preencher a Pessoa com o seu objeto Cidade. Pronto, vc acabou de fazer um lazy loading manual (o hibernate faz isso de forma automática o que é uma merda na minha humilde opinião).

Assim por exemplo quando vc tem que carregar uma lista de pessoas, vc não vai carregar os objetos que a Pessoa possui dentro dela, pois podem haver vários objetos dentro um do outro e carregar a hierarquia completa vai ser um peso grande, sem falar em referências em ciŕculo.

Quando vc carrega uma pessoa só vc pode então fazer um eager loading e carregar tudo se quiser ou precisar. (Vc escolhe o que carregar sempre, no seu DAO)

O principal que você precisa entender aqui é que há dois casos distintos:

  1. O objeto pertence a uma lista estática, como é o caso de Cidade, ou seja, isso muito provavelmente vai estar cacheado em memória.

  2. O objeto é uma entidade dinâmica, que vai estar no banco de dados, ou seja, vc vai precisar fazer uma nova consulta via DAO para carregá-lo (se o DAO vai usar um cache é problema dele).

No caso 1) vc pode converter de ID para Cidade bem rapidamente, em qualquer lugar do seu código, inclusive quando estiver carregando uma lista de Pessoas, pois o custo é muito baixo.

No case 2) vc NÃO pode converter o ID sem ir no banco de dados. O objeto Pessoa poderia ter outro objeto como Endereço por exemplo

A sua idéia é muito boa para o caso 1) mas não é boa para o caso 2), porque acho que não faz sentido instanciar um objeto que possua apenas o campo ID preenchido pela query. Ou talvez tenha. O que vc acha?

Esse exemplo que eu passei da para resolver assim mas tem a situação do meu primeiro post fica mais complicada de se resolver:


Pessoa <- Entidade
      Endereço <-Entidade
             Rua <-Entidade
               id <-Atributo


//Da forma como mostrei vc somente faria:
 BeanConfig config = new BeanConfig(Pessoa.class, "Pessoa"); 
config.field("endereco.rua.id", "cd_rua", DBTypes.INTEGER);

// Da forma atual eu teria que "sujar" a entidade Pessoa com o idRua ou fazer um outro BeanConfig para incluir essa parte do endereço o que resultaria em um insert e um update para incluir somente um registro ou ainda fazer isso atraves de JDBC puro

Outro exemplo:

Problema: Quero salvar na Tabela de Venda o nome do Vendedor!

Organização das Classes


public class Venda{
 private Vendedor vendedor;
...
}

public class Vendedor{
private Pessoa pessoa;
...
}

public class Pessoa{
private nome;
...
}

//Da forma como mostrei vc somente faria:  
BeanConfig config = new BeanConfig(Venda.class, "venda");   
config.field("vendedor.pessoa.nome", "nm_vendedor", DBTypes.String);

//Da forma atual eu não teria uma solução mais simples para o caso, todas as soluções me remetem a um esforço adicional

Perceba que isso somente interfere na forma de gravar, quando for carregar o objeto se vc quiser o nome do Vendedor não vai ter como buscar direto la da Tabela Venda, vai ter que fazer um lazy loading manual para buscar o objeto Vendedor…

Eu ainda prefiro a minha solução. Não há esforço adicional nenhum.

Veja se vc concorda:

  • Vc quer salvar o nome do Vendedor na tabela de vendas.

  • Então vc adiciona um campo extra no seu objeto Venda chamado nomeDoVendedor.

  • Configura o BeanConfig para mapear esse campo “nomeDoVendedor” para o campo na tabela do banco.

  • Quando vc carrega ela já vem para vc de mão beijada.

  • Quando vc vai salvar, vc tem que se lembrar de popular esse campo de alguma maneira.

A sua sugestão tem dois problemas:

  1. Na hora de inserir no banco, vc precisa preencher / carregar a hierarquia inteira quando vc só precisa salvar o nome do vendedor na tabela.

  2. Não funciona na hora de carregar. A minha solucão funciona. :slight_smile:

A minha solução tem apenas um problema, que acho não é propriamente um problema: vc tem uma redundancia no seu objeto, pois o nomeDoVendedor vai aparecer duas vezes, nesse campo adicional e no objeto Vendedor.

Concordo com a sua solução, ela funciona direitinho mas gostaria de trocar mais umas ideias sobre a minha abordagem

Essa situação é o padrão né raramente vc pega um atributo de um objeto assim sem ter a hierarquia completa

Eu tive pensando na hora de carregar também funciona se não me engano vc consegue instanciar um objeto por reflection… vou ver se consigo fazer alguma coisa desse tipo