Criticas, Sugestoes, Dicas na minha Aplicação - Padrão MVC

55 respostas
InSeOfKn

Ola, a uns dias atras estudei sobre MVC mas não consigo ainda pensa como deixar minha Visão totalmente independente do meu modelo, mas mesmo assim resolvi começar a fazer meu aplicativo que na verdade ele vai servir pra controlar caixa, entrada e saida de merdadoria, estoque, clientes e fornecedores.

Vamos ao que eu já fiz (resumo)

DAO generico

public class GenericDAO<T, PK extends Serializable> {
	private Class<?> persistentClass;
	private Session session;

	public GenericDAO(){}

	public GenericDAO(Class<?> persistentClass){
		this.setPersistentClass(persistentClass);
	}

	public GenericDAO(Class<?> persistentClass, Session session){
		this.setPersistentClass(persistentClass);
		this.session = session;
	}

	public void setPersistentClass(Class<?> persistentClass) {
		this.persistentClass = persistentClass;
	}

	public Class<?> getPersistentClass() {
		return persistentClass;
	}

	public void setSession(Session session){
		this.session = session; 
	}

	public Session getSession(){
		return session;
	}

	public T get(PK id){
		@SuppressWarnings("unchecked")
		T object = (T) getSession().get(getPersistentClass(), id);
		return object;
	}

	public void set(T obj, Transaction transaction){
		getSession().saveOrUpdate(obj);
		getSession().flush();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getAll(){
		Criteria criteria = getSession().createCriteria(getPersistentClass());
		return criteria.list();
	}
}

Interfase Controle (ainda incompleta)

public interface Controle<T> {
	public List<T> getAll();
}

Controle dos Clientes (ainda incompleto)

public class ControleCliente implements Controle<Cliente>{
	final GenericDAO<Cliente, Long> dao = new GenericDAO<Cliente, Long>(
			Cliente.class, HibernateUtil.getSession());
	
	public ControleCliente(){
	}
	
	public List<Cliente> getAll(){
		return dao.getAll();
	}
	
	public Double getAReceber(Cliente cliente){
		double aReceber = 0;
		for(Venda venda : cliente.getVendas()){
			for(Saida saida : venda.getSaidas()){
				aReceber += saida.getPesoSaco()*saida.getQuant()*saida.getPreco();
			}
			for(Recebimento rec : venda.getRecebimentos()){
				aReceber -= rec.getValor();
			}
		}
		return aReceber;
	}
	
}

Enum com as colunas do TableModel

@SuppressWarnings("unchecked")
public enum TableColumnsVer implements Coluna<Cliente> {
	NOME {
		@Override
		public Class<?> getColumnClass() {
			return String.class;
		}

		@Override
		public String getColumnName() {
			return "Nome";
		}

		@Override
		public Object getValue(Cliente row) {
			return row.getNome();
		}
	},
	TEL_1 {
		@Override
		public Class<?> getColumnClass() {
			return String.class;
		}

		@Override
		public String getColumnName() {
			return "Telefone";
		}

		@Override
		public Object getValue(Cliente row) {
			return row.getTel_1();
		}
	},
	TEL_2 {
		@Override
		public Class<?> getColumnClass() {
			return String.class;
		}

		@Override
		public String getColumnName() {
			return "Telefone";
		}

		@Override
		public Object getValue(Cliente row) {
			return row.getTel_2();
		}
	},
	A_RECEBER {
		@Override
		public Class<?> getColumnClass() {
			return Double.class;
		}

		@Override
		public String getColumnName() {
			return "A receber";
		}

		@Override
		public Object getValue(Cliente row) {
			return getControle().getAReceber(row);
		}
	};

	public ControleCliente controleCliente;
	
	@Override
	public int getModelIndex() {
		return this.ordinal();
	}

	@Override
	public int getWidth() {
		return 50;
	}
	
	@Override
	public ControleCliente getControle(){
		if(controleCliente == null){
			controleCliente = new ControleCliente();
		}
		return controleCliente;
	}

}

Visão dos Clientes

public class Ver extends JPanel {
	private JScrollPane scrTbl;
	private JTable tbl;
	private JPanel pBts;
	private JButton bVer;
	private JButton bEditar;
	private JButton bAdd;
	private TableModel<Cliente> tblModel;

	private ControleCliente controleCliente;
	public Ver(){
		super();
		inicia();
	}

	private void inicia(){
		this.setLayout(new BorderLayout());
		this.add(getScrTbl(), BorderLayout.CENTER);
		this.add(getPBts(), BorderLayout.SOUTH);
	}
	private JPanel getPBts() {
		if(pBts == null){
			pBts = new JPanel();
			pBts.add(getBVer());
			pBts.add(getBEditar());
			pBts.add(getBAdd());
		}
		return pBts;
	}

	private JButton getBVer() {
		if(bVer == null){
			bVer = new JButton("Ver Vales");
		}
		return bVer;
	}

	private JButton getBEditar() {
		if(bEditar == null){
			bEditar = new JButton("Editar");
		}
		return bEditar;
	}

	private JButton getBAdd() {
		if(bAdd == null){
			bAdd = new JButton("Novo Cliente");
		}
		return bAdd;
	}

	private JScrollPane getScrTbl(){
		if (scrTbl == null) {
			scrTbl = new JScrollPane();
			scrTbl.setViewportView(getTbl());
		}
		return scrTbl;
	}

	private JTable getTbl() {
		if(tbl==null){
			tbl = new JTable();
			tbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			tbl.setModel(getTblModel());
			
		}
		return tbl;
	}

	private TableModel<Cliente> getTblModel() {
		if(tblModel==null){
			tblModel = new TableModel<Cliente>(getControle().getAll(), TableColumnsVer.values());
		
		}
		return tblModel;
	}
	
	private ControleCliente getControle(){
		if(controleCliente == null){
			controleCliente = new ControleCliente();
		}
		return controleCliente;
	}
	
}

bom essas são algumas class da minha aplicação mas já da de vê como ta ficando minha estrutura

Mas oque eu gostaria de ter certeza é o seguinte

:arrow: O modelo ficam com as class de persistência (que representam as tabelas do banco), com os DAO e com o HiberneitUtil
:arrow: O controle e o responsável de por métodos como obterTodos() (mas não fazer a busca no banco, mas sim pedir ao DAO), abrir e fechar as sessões e as transações, fazer cálculos com os dados pegos dos DAOs (como receber o preço de cada produto e multiplicar pela quantidade) e tratar as acessões
:arrow: A visão fica responsável, somente por montar a interface gráfica tendo direito a somente acessar métodos do controle e exibir os eros pro usuário tratados pelo controle

Montei minha aplicação pensando nesses conceitos mas um eu não consegui cumprir o de usar somente métodos do controle na visão pois não consigo pensar em um jeito de no enum das colunas não usar métodos como getNome() que é da class cliente que fica no modelo.

Gostaria de saber se isso quebra o padrão MVC e se o que eu penso sobre MVC está coreto??

Até!

55 Respostas

J

Não utilize os enums para seu table model, pelo jeito vc deve estar usando o auto-filtro do ViniGodoy aqui do forúm. Utilize o ObjectTableModel do projeto Towel do Mark (aqui do forúm tbm…) que inclusive já está com as classes do auto-filtro do ViniGodoy.

Link do projeto Towel (ObjectTableModel): http://www.guj.com.br/java/227402-markutils-sob-novo-nome/1

Sobre o MVC dá uma olhadinha nesse tutorial aqui http://www.oracle.com/technetwork/articles/javase/mvc-136693.html. É da propria oracle mostrando como aplicar o MVC com o PropertyChangeSupport da própria API.

Eu particularmente já ví vários outros tipos de aplicação do MVC, mas gostei muito desse.

x111

Primeira coisa: a sua lógica do dominio esta vazando para o controle:

public Double getAReceber(Cliente cliente){
		double aReceber = 0;
		for(Venda venda : cliente.getVendas()){
			for(Saida saida : venda.getSaidas()){
				aReceber += saida.getPesoSaco()*saida.getQuant()*saida.getPreco();
			}
			for(Recebimento rec : venda.getRecebimentos()){
				aReceber -= rec.getValor();
			}
		}
		return aReceber;
}

Para ter uma base de como funciona o MVC você tem que conhecer antes os padrões de projeto então leia Use a cabeça Padrões de Projeto
Para não ter objetos anêmicos evitar que a lógica do domínio se misture com a lógica de infraestrutura leia Domain Driven Design do Eric Evans

InSeOfKn

bom primeiro desculpa a demora para retornar

joyle não estou usando o alto filtro do ViniGodoy nem mesmo o ColumnModel (acho que é esse o nome) dele, esse é um TableModel que eu mesmo fiz, mas porque não se deve usar Enums??

Vou até tentar ler o link recomendado, mas é difícil o meu inglês é muito fraco.

Valeu!

x@ndy tu diz que a lógica do domínio deveria ficar no modelo?

mas o que é a logica de domínio, os cálculos feitos com os dados do banco??

não achei material online sobre “logica de domínio”, teria outro termo que signifique a mesma coisa??

Sobre os livros to sem grana pra comprar, mas pesquisando aqui na rede de bibliotecas da escola achei o Use a cabeça Padrões de Projeto, agora me resta saber o endereço dessa biblioteca!

Até

InSeOfKn

joyle tentando ler o link indicado fiquei com uma duvida quem deve estender AbstractModel as class de persistência ou os DAOs??

Pensei que fosse nas class de persistência mas me dei conta que alterar os atributos ali não altera os dados no banco, dai passei a achar que fosse nos DAOs mas os métodos deles se resumem a atualizar (que recebe uma class de persistência como parâmetro), adicionar (que recebe uma class de persistência como parâmetro), obter (que recebe um long como parâmetro) e obterTodos(sem parâmetros), qual seria a saída??

[edit]Agora me passou pela cabeça em colocar nas class de persistências e os métodos setter dela chamarem o DAO, acho que até funcionaria mas isso não estaria totalmente fora de padrão(gambiarra)??[/edit]

Até!

esmiralha

InSeOfKn:

x@ndy tu diz que a lógica do domínio deveria ficar no modelo?

mas o que é a logica de domínio, os cálculos feitos com os dados do banco??

não achei material online sobre “logica de domínio”, teria outro termo que signifique a mesma coisa??

Sobre os livros to sem grana pra comprar, mas pesquisando aqui na rede de bibliotecas da escola achei o Use a cabeça Padrões de Projeto, agora me resta saber o endereço dessa biblioteca!

Até

Lógica de domínio são as regras de negócio do seu sistema. Imagine um jogo 3D. Todo jogo tem regras, certo? Bom, as regras do jogo são parte da lógica de domínio.

ViniGodoy

Também gostaria de saber. Eu mesmo tenho um TableModel onde as colunas são descritas por enums, como vc fez. Na verdade, ele é descrito por uma lista de uma interface chamada Column, e o enum é só uma maneira conveniente de implementar essa lista (como vc fez tb).

E PS: É auto-filtro. O filtro é automático, não grande. :slight_smile:

J

Desculpe, na verdade queria dizer que você deve evitar nesse caso! Note, se vc tem suas tabelas com mais de 30 campos por exemplo, imagina escrever enums com mais de 30 campos para sua tabela! Disse isso por que isso é só um pouco chato e cansativo :wink:
Os enums resolvem essa situação de forma elegante, mas o modelo que o Mark propõe é bem melhor que ficar escrevendo enums. :wink:

De uma olhada no projeto Towel no link que te passei anteriormente.

J

InSeOfKn:
joyle tentando ler o link indicado fiquei com uma duvida quem deve estender AbstractModel as class de persistência ou os DAOs??

Pensei que fosse nas class de persistência mas me dei conta que alterar os atributos ali não altera os dados no banco, dai passei a achar que fosse nos DAOs mas os métodos deles se resumem a atualizar (que recebe uma class de persistência como parâmetro), adicionar (que recebe uma class de persistência como parâmetro), obter (que recebe um long como parâmetro) e obterTodos(sem parâmetros), qual seria a saída??

[edit]Agora me passou pela cabeça em colocar nas class de persistências e os métodos setter dela chamarem o DAO, acho que até funcionaria mas isso não estaria totalmente fora de padrão(gambiarra)??[/edit]

Até!

Seus models devem estender o AbstractModel! No AbstractModel existe um método chamado firePropertyChange(String propertyName, Object oldValue, Object newValue) que deve chamado pelo seu model toda vez que ocorre uma mudança nele e isso interfere na renderização do seu model, então é necessário notificar a view.

No meu caso, eu deixo o controller responsável por chamar o DAO e passar o objeto a ser persistido.

Acredito que sim. Se vc fizer isso, toda vez que vc alterar seu atributo, vc terá que persistir seu model, o que é inviável quando não há a real necessidade disso. Persista somente quando necessário.

J

Ops… :lol: . Consertei lá em cima.

J

Acho interessante falar também do Binder do projeto Towel, ele é bem interessante de se trabalhar e evita escrever um monte de propriedades como o PropertyChangeSupporte propõe

Dá uma olhada aqui nesse link : http://markytechs.wordpress.com/2010/03/03/binder-2-0-agora-com-annotations/

Você atualiza suas views e seus models de uma maneira bem mais fácil e elegante também.

Ainda estou testando e é bem legal mesmo.

InSeOfKn

Ta, mas eu estenderia AbstractModel em todas as class que pertence ao modelo, entre elas as class de persistência (as que são anotadas com @Entity), os DAOs até mesmo o HibernateUtil??
acredito que não pois nem todas notificam mudanças, na verdade a únicas que modificam o banco são os DAOs mas eles não sabem que propriedade foi modificada, já que as propriedades estão das class de persistência a que o DAO já recebe atualizada mas ainda não persistida

Até

J

InSeOfKn:
joyle:

Seus models devem estender o AbstractModel! No AbstractModel existe um método chamado firePropertyChange(String propertyName, Object oldValue, Object newValue) que deve chamado pelo seu model toda vez que ocorre uma mudança nele e isso interfere na renderização do seu model, então é necessário notificar a view.

Ta, mas eu estenderia AbstractModel em todas as class que pertence ao modelo, entre elas as class de persistência (as que são anotadas com @Entity), os DAOs até mesmo o HibernateUtil??
acredito que não pois nem todas notificam mudanças, na verdade a únicas que modificam o banco são os DAOs mas eles não sabem que propriedade foi modificada, já que as propriedades estão das class de persistência a que o DAO já recebe atualizada mas ainda não persistida

Até

Não, somente os seus models é que vão estender do AbstractModel. Somente o model deve notificar a view de mudanças.
Os DAOs não sabem e nem devem saber se o model foi modificado ou não, eles são apenas para persistir os dados e é você que define quando eles irão persistir.

Posso estar enganado, mas acredito que você está com um pouco de dificuldades para aplicar o padrão. Dê uma lidinha a mais no tutorial, lá tem também o código fonte contendo todo o exemplo, baixe-o e teste. Há outros links sobre MVC lá também dê uma lida.

InSeOfKn

Mas o que seria o Model? não seria o M do (MVC)? se for os DAOs não fazem parte de dele?

Até!

J

InSeOfKn:
Mas o que seria o Model? não seria o M do (MVC)? se for os DAOs não fazem parte de dele?

Até!

O model é a sua classe de negócio, que também pode ser mapeada para ser relacionada com o banco.

Você está utilizando algum framework como Hibernate por exemplo? As classes POJOS do hibernate é que eu extendo do AbstractModel e quando executo algum set ou algum outro método que mude o estado do objeto eu chamo o firePropertyChange.

InSeOfKn

Deixa eu ver se entendi, O Model é as Class de persistência (não sei esse o nome são as class anotadas com @Entity) junto com os métodos de negocio como aReceber() entre outros

O DAO não faz parte do Model

É isso???

J

Dá uma olhda nesse link aqui também e vê se te ajuda mais.

http://wiki.sintectus.com/bin/view/GrupoJava/MVC

J
InSeOfKn:
Deixa eu ver se entendi, O Model é as Class de persistência (não sei esse o nome são as class anotadas com @Entity) junto com os métodos de negocio como aReceber() entre outros

O DAO não faz parte do Model

É isso???

Isso. O DAO não faz parte do model não, ele é apenas para persistir o model com o banco.

Esse aqui é um exemplo do DAO que utilizo para gravar os bancos por exemplo.
/*
package com.jns.bancos;

import com.jns.util.AbstractDAO;
import com.jns.util.AbstractModel;
import com.jns.util.CrudView;

public class BancosDAO extends AbstractDAO {

    public BancosDAO(CrudView view) {
        this.view = view;
    }

    public void recordSave(AbstractModel bancoObject) {
        if (bancoObject instanceof BancosModel) {
            try {
                sessionOpen();
                transactionBegin();

                getSession().save(bancoObject);

                transactionCommit();
                sessionClose();
            } catch (Exception e) {                
            }
        } else {
            throw new IllegalArgumentException("O argumento não é uma " + BancosModel.class);
        }
    }

    public void recordDelete(AbstractModel bancoObject) {
        if (bancoObject instanceof BancosModel){
            try {
                sessionOpen();
                transactionBegin();

                getSession().delete(bancoObject);

                transactionCommit();
                sessionClose();
            } catch (Exception e) {                
            }
        } else {
            throw new IllegalArgumentException("O argumento não é uma " + BancosModel.class);
        }
    }

    public void recordUpdate(AbstractModel bancoObject) {
        if (bancoObject instanceof BancosModel){
            try {
                sessionOpen();
                transactionBegin();

                getSession().saveOrUpdate(bancoObject);

                transactionCommit();
                sessionClose();
            } catch (Exception e) {
            }
        } else {
            throw new IllegalArgumentException("O argumento não é uma " + BancosModel.class);
        }
    }

    public boolean recordExists(AbstractModel object) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
}
InSeOfKn

Eu estou usando o Hibernate você teria um exemplo de uma class POJO(que té então estava chamando de class de persistência) para min ver como fica ele estendendo AbstractModel??

J
InSeOfKn:
Eu estou usando o Hibernate você teria um exemplo de uma class POJO(que té então estava chamando de class de persistência) para min ver como fica ele estendendo AbstractModel??

Claro. Tá aí um protótipo.

import com.jns.util.AbstractModel;
import com.towel.el.annotation.Resolvable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="bancos")
public class BancosModel extends AbstractModel implements java.io.Serializable {

    @Resolvable(colName="ID Banco:")
    private Integer bancoId;

    @Resolvable(colName="Cód. Banco:")
    private String bancoCodBanco;

    @Resolvable(colName="Nome Banco:")
    private String bancoNome;

    @Resolvable(colName="Web Site:")
    private String bancoWebsite;

    public BancosModel() {
    }

	
    public BancosModel(int bancoId, String bancoCodBanco, String bancoNome) {
        this.bancoId = bancoId;
        this.bancoCodBanco = bancoCodBanco;
        this.bancoNome = bancoNome;
    }
    public BancosModel(int bancoId, String bancoCodBanco, String bancoNome, String bancoWebsite) {
       this.bancoId = bancoId;
       this.bancoCodBanco = bancoCodBanco;
       this.bancoNome = bancoNome;
       this.bancoWebsite = bancoWebsite;
    }
   
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="banco_id", unique=true, nullable=false)
    public Integer getBancoId() {
        return this.bancoId;
    }
    
    public void setBancoId(Integer bancoId) {
        Integer oldId = this.bancoId;
        this.bancoId = bancoId;
        firePropertyChange(BancosController.BANCO_ID_PROPERTY, oldId, bancoId);
    }
    
    @Column(name="banco_cod_banco", nullable=false, length=5)
    public String getBancoCodBanco() {
        return this.bancoCodBanco;
    }
    
    public void setBancoCodBanco(String bancoCodBanco) {
        String oldCodBanco = this.bancoCodBanco;
        this.bancoCodBanco = bancoCodBanco;
        firePropertyChange(BancosController.BANCO_COD_PROPERTY, oldCodBanco, bancoCodBanco);
    }
    
    @Column(name="banco_nome", nullable=false)
    public String getBancoNome() {
        return this.bancoNome;
    }
    
    public void setBancoNome(String bancoNome) {
        String oldBancoNome = this.bancoNome;
        this.bancoNome = bancoNome;
        firePropertyChange(BancosController.BANCO_NOME_PROPERTY, oldBancoNome, bancoNome);
    }
    
    @Column(name="banco_website")
    public String getBancoWebsite() {
        return this.bancoWebsite;
    }
    
    public void setBancoWebsite(String bancoWebsite) {
        String oldBancoWebSite = this.bancoWebsite;
        this.bancoWebsite = bancoWebsite;
        firePropertyChange(BancosController.BANCO_WEBSITE_PROPERTY, oldBancoWebSite, bancoWebsite);
    }

}

Mas antes de sair fazendo um monte de POJOs por aí veja esse link abaixo.
[url]http://blog.caelum.com.br/nao-aprender-oo-getters-e-setters/[/url]

InSeOfKn

Obrigado! mas olhando seu DAO não encontrei getter com getAll(), get(Long id) etc… com quem ficaria essa responsabilidade??

[edit]ontem mesmo li esse link http://blog.caelum.com.br/nao-aprender-oo-getters-e-setters/ e percebi que meus POJOs estão com setters a mais[/edit]

J
InSeOfKn:
Obrigado! mas olhando seu DAO não encontrei getter com getAll(), get(Long id) etc.. com quem ficaria essa responsabilidade?? [edit]ontem mesmo li esse link http://blog.caelum.com.br/nao-aprender-oo-getters-e-setters/ e percebi que meus POJOs estão com setters a mais[/edit]

Fica no AbstractDAO, se vc notar estou extendendo de AbstractDAO.

Vou postar pra vc ver, mas ainda está em desenvolvimento e falta implementar paginação nas pesquisas.
As rotinas de busca que tenho até agora são findByProperty(Class modelClass, String modelPropertyName, Object object) que é uma busca bem genérica, é só passar a Class do model, o atributo e o valor a ser buscado e aí uso o hibernate pra fazer o resto.Prefiro fazer assim do que ficar implementando um monte de busca praticamente igual para todas as telas de pesquisas. Esse método busca em qualquer tabela bastando apenas o model estar mapeado.
Os métodos findByDate (ainda não testei) e o findAll também funcionam da mesma maneira.

Tá aí a classe, mas ainda está em desenvolvimento.

package com.jns.util;

import com.jns.config.banco.HibernateUtil;
import java.awt.Component;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import javax.swing.JOptionPane;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

/**
 * Contém métodos que podem ser executados em todos os DAOs
 * @author Joyle
 */
public abstract class AbstractDAO implements CrudActionsDAO, CrudActionsFindDAO {

    private Session session = null;
    private Transaction transaction = null;
    protected CrudView view;

    public void cancelQuery(){
        try {
            getSession().cancelQuery();
        } catch (Exception e) {
            JOptionPane.showMessageDialog((Component)this.view, "Houve um erro ao cancelar a query.\n\nErro:\n" + e + "\n\nContate o administrador do sistema.", "Erro de cancelamento.", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Return the Session
     * @return <strong>Session</strong> - If session not null.<br>
     * @return <strong>Null</strong> - If session is null.
     */
    protected Session getSession(){
        if (session != null)
            return session;
        return null;
    }

    /**
     * Return the Transaction
     * @return <strong>Transaction</strong> - If transaction not null.<br>
     * @return <strong>Null</strong> - If transaction is null.
     */
    protected Transaction getTransaction(){
        if (transaction != null)
            return transaction;
        return null;
    }

    /**
     * Abre uma sessão com o banco de dados.
     */
    protected void sessionOpen(){
        if (session == null)
            session = HibernateUtil.getSessionFactory().openSession();
    }

    /**
     * Fecha a sessão com o banco de dados.
     */
    protected void sessionClose(){
        if (session != null)
            session.close();
        session = null;
    }

    /**
     * Inicia uma trasação.
     */
    protected void transactionBegin(){
        if (session != null)
            transaction = session.beginTransaction();
    }

    /**
     * Commita os dados da trasação no banco de dados.
     */
    protected void transactionCommit(){
        if (transaction != null)
            transaction.commit();
    }

    /**
     * Executa o rollback.
     */
    protected void transactionRollBack(){
        if (transaction != null)
            transaction.rollback();
    }

    public List findByProperty(Class modelClass, String modelPropertyName, Object object) {
        boolean propertyExists = false;
        Criteria propertyCriteria;
        List results = null;

        try {
            for (Field field : modelClass.getDeclaredFields()) {
                if (field.getName().equals(modelPropertyName)) {
                    propertyExists = true;
                    break;
                }
            }

            if (!propertyExists) {
                throw new NoSuchFieldException("The property \"" + modelPropertyName + "\" does not exist in " + modelClass);
            } else {
                sessionOpen();
                transactionBegin();

                propertyCriteria = getSession().createCriteria(modelClass, "model");
                
                if (object instanceof String || object instanceof Character) {
                    propertyCriteria.add(Restrictions.ilike("model."+modelPropertyName, String.valueOf(object).trim(), MatchMode.ANYWHERE));

                } else if (object instanceof Integer || object instanceof Long || object instanceof Double || object instanceof Float) {
                    propertyCriteria.add(Restrictions.eq("model."+modelPropertyName, object));

                } else {
                    throw new UnsupportedOperationException("Type \"" + object.getClass().getName() + "\" not supported yet.");
                }

                results = propertyCriteria.list();
                sessionClose();

                return results;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return results;
        }
    }

    public List findByDate(Class modelClass, String modelPropertyDateName, Date date1, Date date2) {
        boolean propertyExists = false;
        Criteria propertyCriteria;
        List results = null;

        try {
            for (Field field : modelClass.getDeclaredFields()) {
                if (field.getName().equals(modelPropertyDateName)) {
                    propertyExists = true;
                    break;
                }
            }

            if (!propertyExists){
                throw new NoSuchFieldException("The property \"" + modelPropertyDateName + "\" does not exist in " + modelClass);
            } else {
                sessionOpen();
                transactionBegin();

                propertyCriteria = getSession().createCriteria(modelClass, "model");
                propertyCriteria.add(Restrictions.between("model." + modelPropertyDateName, date1, date2));

                results = propertyCriteria.list();

                sessionClose();
                return results;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return results;
        }
    }

    public List findAll(Class modelClass) {
        List results;

        sessionOpen();
        transactionBegin();

        results = getSession().createCriteria(modelClass).list();
        sessionClose();

        return results;
    }

}

Algumas coisas anotei em portugues e outras em inglês mesmo. Depois tenho que mudar isso.

InSeOfKn

Obrigado joyle, agora com o material que me enviasse vou trabalhar em cima e quando conseguir algo que seja visível eu volto a postar para uma nova avaliação!

Obrigado x@ndy e VineGodoy pela participação de vocês!

Até!

InSeOfKn

Olha eu aqui incomodando de novo :smiley:

adaptando os exemplos aqui postados não consegui montar um jeito de notificar a View quando um objeto for incluindo ou excluído do banco

poderiam me mostrar?

InSeOfKn

Outra duvida como fazer pra adicionar os Models no Controller
A View eu passei um controller como parâmetro e no construtor eu já chamei o controller.addView(this), mas no Model eu não posso fazer isso porque o Hibernate obriga a ter um construtor sem parâmetro e mesmo se eu criasse outro construtor com parâmetro seria o sem parâmetro que seria chamado pelo criteria

O que devo fazer?

J

Instancie seu model e dê um controller.addModel(model).

InSeOfKn

Mas quem instancia meu model é o próprio hiberneite no método list() por exemplo é instanciado o model quantas linhas a pesquisa retornar.

Pensei em guardar uma instancia de cada controller em uma variável statica e adicionar e model e view por ela, não tem problema fazer isso?

InSeOfKn

Testando guardando uma referencia a uma instancia do controller obtive outro problema ao mandar atualizar o controller atualizar uma propriedade no model ele atualiza essa propriedade em todas as instancias, por exemplo ao selecionar uma linha na tabela que exibe os clientes e clicar no botão aditar e mudar o nome todos os clientes mudam de nome.

Para ser bem sincero esse padrão MVC já ta me deixando maluco, principalmente como eles devem se comunicar sei que tudo deve passar pelo controller (acho) mas fica complicado por meio de um único método (setModelProperty(String propertyName, Object newValue):wink: o controle notificar todas as mudanças já que ele tem registrado um monte de Model do qual eu sinto uma dificuldade imensa de destingi-los.

Formulando melhor minha pergunta: o que devo fazer para meu controller conseguir lidar com um fluxo gigante de informação mandadas pela view e pelo model que esperam que a mensagem de um chegue no outro sem nem saber que o outro existe? já que o controller trabalha como um carteiro que tenta entregar cartas sem endereço.

Até!

J

Ele está fazendo isso porque você não está restringindo a mudança na tela de pesquisa somente a linha que contém o determinado valor a ser mudado. Eu resolvo isso comparando os IDs, mesmo que o ID não esteja sendo exibido na sua JTable ele está no seu model.

Você tem que programar o comportamento que cada view tomará quando ela for atualizada. O model só se encarrega de notificar as mudanças, mas somente a view sabe como ela se comporta.

Muito pelo contrário. O seu controller sabe exatamente onde entragar as cartas, por isso você registra as views e os models.

InSeOfKn

Mas isso não traria uma certa dependência entre o Model e o Controller já que o Model vai ser obrigado a ter um método que retorne o Id e esse método vai ter que ter exatamente a mesma nomenclatura em todas as class do Model assim perdendo a autonomia do Model impedindo que em uma class o nome seja getId na outra getIdPessoa

joyle:

Muito pelo contrário. O seu controller sabe exatamente onde entragar as cartas, por isso você registra as views e os models.

mas eu posso ter milhares de instancias de models e centenas de views registradas em um único controller percorrer por loops para notificar pode ser um custo (de tempo de processo) grande de mais e alem disso ter que verificar uma a uma para ver qual ele deve notificar pode ampliar o custo, pois como recomendado o carteiro (controller) tem que abrir carta por carta ver o conteúdo e verificar na sua lista qual quer receber essa carta!

J

InSeOfKn:
joyle:

Ele está fazendo isso porque você não está restringindo a mudança na tela de pesquisa somente a linha que contém o determinado valor a ser mudado. Eu resolvo isso comparando os IDs, mesmo que o ID não esteja sendo exibido na sua JTable ele está no seu model.

Mas isso não traria uma certa dependência entre o Model e o Controller já que o Model vai ser obrigado a ter um método que retorne o Id e esse método vai ter que ter exatamente a mesma nomenclatura em todas as class do Model assim perdendo a autonomia do Model impedindo que em uma class o nome seja getId na outra getIdPessoa

Não, você pode dizer exatamente como sua view deverá funcionar quando o model for atualizado. Isso independe como você irá fazer isso, dei o exemplo do ID, mas você pode fazer como quiser.
E não, o model não tem que necessariamente ter um método que retorne o ID.

InSeOfKn:

joyle:

Muito pelo contrário. O seu controller sabe exatamente onde entragar as cartas, por isso você registra as views e os models.

mas eu posso ter milhares de instancias de models e centenas de views registradas em um único controller percorrer por loops para notificar pode ser um custo (de tempo de processo) grande de mais e alem disso ter que verificar uma a uma para ver qual ele deve notificar pode ampliar o custo, pois como recomendado o carteiro (controller) tem que abrir carta por carta ver o conteúdo e verificar na sua lista qual quer receber essa carta!


Milhares de instância de models? Você trabalha com o mesmo model para as views que o renderizam.
Outra coisa é um custo GRANDE de performance… de quantas views estamos falando? mais de 100 pra um model por exemplo? :wink:

Resumindo essa questão de performance, isso é realmente um dos pontos negativos de MVC já que vc utiliza o mesmo model para varias views. Mas pra isso ser algo realmente significativo… :shock:

J

Dá uma olhada nesse tópico aqui : http://www.guj.com.br/java/129277-perguntas-sobre-mvc-desktop-existe-solucao–mvpmvc-webobserver-e-exceptions

InSeOfKn

No caso do meu sistema que eu to montando performasse não é o problema pois ele é um sistema pequeno mas agora imagina um sistema grande que guarde uns 3 milhões de clientes e eu tenha uma view para exibir e outra para editar um especifico

Por exemplo ao mandar editar José Silva, editar e clicar em salvar o controller vai ter que percorrer esses 3 milhões em um loop até achar um que o atributo de identificação seja igual isso levaria um tempinho né?

Mas achei a solução mudei de ideia sobre guardar o controller em uma constante isso faz com que meu controller trabalhem com todas as instancias de model sempre e agora trabalho com varias instancias de controller e cada instancia só tem registrado os models e as view que ele ira trabalhar assim a view editar terá uma instancia de controller que só tem o model que esta sendo editado e a view editar sem presisar saber que os outros model e as outras view existem!

[quote = joyle]Dá uma olhada nesse tópico aqui : http://www.guj.com.br/java/129277-perguntas-sobre-...vpmvc-webobserver-e-exceptions
[/quote]ontem fui até as 5 lendo esse topico :smiley:

Até estou aperfeiçoando aqui o que consegui fazer e já posto!

J

InSeOfKn:
Por exemplo ao mandar editar José Silva, editar e clicar em salvar o controller vai ter que percorrer esses 3 milhões em um loop até achar um que o atributo de identificação seja igual isso levaria um tempinho né?

Pra isso existe paginação! E outra que, sinceramente, você não está pensando em exibir 3 milhões de registros de uma só vez? :shock:

Acho que você está confundindo as coisas sobre trabalhar com várias instâncias do controller. Se o controller tiver várias instâncias, você não conseguirá notificar suas view que estão carregando uma outra instância do controller (do mesmo tipo) e por sua vez uma outra instância do model (do mesmo tipo).

Assim você complica mais sua vida! Pra que carregar várias instâncias do mesmo controller?

InSeOfKn

Como prometido estou aqui postando o que fiz!

Modelo:

Cliente:
@Entity
@PrimaryKeyJoinColumn(name = "id_cliente")
public class Cliente extends Pessoa{
	private static final long serialVersionUID = 4527755045671933073L;

	@OneToMany(mappedBy="cliente", fetch = FetchType.LAZY)
	@Cascade(CascadeType.ALL)
	private Collection<Venda> vendas;
	
	public Cliente() {}

	public Collection<Venda> getVendas() {
		return vendas;
	}		
}
Pessoa:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Pessoa extends AbstractModel implements Serializable {
	private static final long serialVersionUID = 5546109411213254415L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id_pessoa")
	private Long id;
	@Column(unique = false, nullable = false)
	private String nome;
	@Column(unique = false, nullable = true)
	private String tel_1;
	@Column(unique = false, nullable = true)
	private String tel_2;
	@Column(unique = false, nullable = true)
	private String doc;
	@OneToOne
	@Cascade(CascadeType.ALL)
	@JoinColumn(name="id_endereco")
	private Endereco endereco;
	
	public Pessoa() {}
	
	public Long getId() {
		return id;
	}
	
	public String getNome() {
		return nome;
	}
	
	public void setNome(String nome) {
		try {
			if(this.nome == null) System.out.println("Null this.nome");
			String oldNome = this.nome;
			this.nome = nome;
			firePropertyChange(ClienteController.NOME_PROPERTY, oldNome, nome);
		} catch (Exception e) {
			System.out.println("Erro no cliente");
			e.printStackTrace();
		}
	}
	
	public String getTel_1() {
		return tel_1;
	}
	
	public void setTel_1(String tel_1) {
		String oldTel_1 = this.tel_1;
		this.tel_1 = tel_1;
		firePropertyChange(ClienteController.TEL_1_PROPERTY, oldTel_1, tel_1);
	}
	
	public String getTel_2() {
		return tel_2;
	}
	
	public void setTel_2(String tel_2) {
		String oldTel_2 = this.tel_2;
		this.tel_2 = tel_2;
		firePropertyChange(ClienteController.TEL_2_PROPERTY, oldTel_2, tel_2);
	}

	public void setEndereco(Endereco endereco) {
		this.endereco = endereco;
	}

	public Endereco getEndereco() {
		return endereco;
	}

	public void setDoc(String doc) {
		String oldDoc = this.doc;
		this.doc = doc;
		firePropertyChange(ClienteController.DOC_PROPERTY, oldDoc, tel_2);
	}

	public String getDoc() {
		return doc;
	}
	
}

Controller:

ClienteController:
public class ClienteController extends AbstractController {

	public static final String NOME_PROPERTY = "Nome";
	public static final String TEL_1_PROPERTY = "Tel_1";
	public static final String TEL_2_PROPERTY = "Tel_2";
	public static final String DOC_PROPERTY = "Doc";
	
    public void changeNome(String newNome) {
        setModelProperty(NOME_PROPERTY, newNome);
    }

    public void changeTel_1(String newTel_1) {
        setModelProperty(TEL_1_PROPERTY, newTel_1);
    }
    
    public void changeTel_2(String newTel_2) {
        setModelProperty(TEL_2_PROPERTY, newTel_2);
    }
    
    public void changeDoc(String newDoc){
    	 setModelProperty(DOC_PROPERTY, newDoc);
    }
}
AbstractController:
public abstract class AbstractController implements PropertyChangeListener {

	private ArrayList<AbstractViewPane<?>> registeredViews;
	private ArrayList<AbstractModel> registeredModels;

	public AbstractController() {
		registeredViews = new ArrayList<AbstractViewPane<?>>();
		registeredModels = new ArrayList<AbstractModel>();
	}


	public void addModels(Collection<? extends AbstractModel> models) {
		registeredModels.addAll(models);
		for(AbstractModel model : models){
			model.addPropertyChangeListener(this);
		}
	}
	
	public void addModel(AbstractModel model) {
		registeredModels.add(model);
			model.addPropertyChangeListener(this);
	}

	public void removeModel(AbstractModel model) {
		registeredModels.remove(model);
		model.removePropertyChangeListener(this);
	}

	public void addView(AbstractViewPane<?> abstractViewPane) {
		registeredViews.add(abstractViewPane);
	}

	public void removeView(AbstractViewPane<?> abstractViewPane) {
		registeredViews.remove(abstractViewPane);
	}


	//  Use this to observe property changes from registered models
	//  and propagate them on to all the views.


	public void propertyChange(PropertyChangeEvent evt) {

		for (AbstractViewPane<?> abstractViewPane: registeredViews) {
			abstractViewPane.modelPropertyChange(evt);
		}
	}


	/**
	 * This is a convenience method that subclasses can call upon
	 * to fire property changes back to the models. This method
	 * uses reflection to inspect each of the model classes
	 * to determine whether it is the owner of the property
	 * in question. If it isn't, a NoSuchMethodException is thrown,
	 * which the method ignores.
	 *
	 * @param propertyName = The name of the property.
	 * @param newValue = An object that represents the new value
	 * of the property.
	 */
	protected void setModelProperty(String propertyName, Object newValue) {

		for (AbstractModel model: registeredModels) {	
				Method method;
				try {
					method = model.getClass().
					getMethod("set"+propertyName, new Class[] {
						newValue.getClass()
					});
					method.invoke(model, newValue);
					System.out.println("Chamado");
				} catch (Exception e) {
					
				}

		}
	}
}

View:

abstractViewPane:
public abstract class AbstractViewPane<T extends AbstractController> extends JPanel{
	private static final long serialVersionUID = 5902448448848829405L;

	protected T controller;

	/**
	 * Called by the controller when it needs to pass along a property change 
	 * from a model.
	 *
	 * @param evt The property change event from the model
	 */

	public abstract void modelPropertyChange(PropertyChangeEvent evt);

	protected AbstractViewPane (T controller){
		this.controller = controller;
		controller.addView(this);
	}
}
Editar: (muito código omitido devido a bagunça feita pela verificação estar na view - sei que ta errado -)
public class Editar extends AbstractViewPane<ClienteController> implements ActionListener, KeyListener{
//Fields omitidos

	public Editar(Cliente cliente, Window window){
		super(new ClienteController());
		controller.addModel(cliente);
		this.setLayout(null);
		this.window = window; 
		this.cliente = cliente;
		inicia();
	}
        //métodos omitidos 

                //parte do código que comunica ao controller as mudanças
		}else{
			if(!this.getTDoc().getText().equals(cliente.getDoc()==null ? "" : cliente.getDoc()))
				controller.changeDoc(this.getTDoc().getText());
			if(!this.getTTel_1().getText().equals(cliente.getTel_1()==null ? "" : cliente.getTel_1()))
				controller.changeTel_1(this.getTTel_1().getText());
			if(!this.getTTel_2().getText().equals(cliente.getTel_2()==null ? "" : cliente.getTel_2()))
				controller.changeTel_2(this.getTTel_2().getText());
			if(!this.getTNome().getText().equals(cliente.getNome()))
				controller.changeNome(this.getTNome().getText());
			window.dispose();
			window = null;
		}
}
Ver:(código omitidos por ser puramente para montar a visão)
public class Ver extends AbstractViewPane<ClienteController> {
        //fields omitidos
	public Ver(){
		super(new ClienteController());
		controller.addModels(getClientes());
		inicia();
	}
        //métodos omitidos
	@Override
	public void modelPropertyChange(PropertyChangeEvent evt) {
		getTblModel().refresh();
	}
}

Peço a vocês uma nova avaliação para eu poder ver se estou no caminho certo! e qualquer, mas qualquer coisa que possa me ajudar e ajudar outras pessoas com a mesma duvida peço que postem!

Obrigado joyle pela sua paciência de ajudar e por acompanhar o tópico sempre respondendo minhas duvidas que não são poucas!

Até

InSeOfKn

joyle:

Acho que você está confundindo as coisas sobre trabalhar com várias instâncias do controller. Se o controller tiver várias instâncias, você não conseguirá notificar suas view que estão carregando uma outra instância do controller (do mesmo tipo) e por sua vez uma outra instância do model (do mesmo tipo).

Assim você complica mais sua vida! Pra que carregar várias instâncias do mesmo controller?

Funcionou! e todas as view interessada foram notificadas! ola como ta a comunicação na imagem em anexo e como foi feito no post acima

J

Bom, se te atendeu assim então tá.
Vou te mostrar como faço aqui e quando tiver mais tempo posto umas classes de exemplo, se vc quiser claro.

InSeOfKn

Atender por atender eu nem tinha criado o tópico já que estava fazendo tudo misturado e possivelmente iria funcionar na pura gambiarra, estou aqui para aprender, pois sei que quando entrar pro mercado de trabalho eles não vão aceitar gambiarra em cima de gambiarra alem de se tornar um código inlegível até para mim mesmo imagina pro resto da equipe! :smiley:

joyle:

Vou te mostrar como faço aqui e quando tiver mais tempo posto umas classes de exemplo, se vc quiser claro.

Vou analisar a imagem e vou tentar implementar do seu jeito para evitar dor de cabeça futuramente, e sim vou querer algumas class de exemplo, toda ajuda é bem vinda!

Obrigado mais uma vez por gastar seu precioso tempo aqui comigo!

Até!

J

Que isso, quando preciso de ajuda o pessoal também faz o mesmo! :smiley:

Mas só lembrando, para cada model você terá um controller! E então você pode ter várias views que renderizam o mesmo model (exemplo acima). Aí então você programa o comportamento de cada view quando o model for atualizado.

InSeOfKn

Isso eu acho que entendi, o que ta pegando agora é como administrar as varias instancias do Model dentro do mesmo Controller

Já que tenho uma constante pra cada Controller e varias instancias de um mesmo Model (uma para cada linha da tabela) adicionadas nessa mesma constante e o que acontece é que quando mando atualizar uma instancia especifica do Model o Controller atualiza todas e isso não é desejado, já tentei identificar pelo id ou por outro atributo mas não sei como o Model vai receber esse atributo nem como ele vai comparar com os demais registrados, ou testar recebendo como parâmetro e lendo por uma Constante no Controller como os demais atributos!

Até!

J

InSeOfKn:
joyle:

Mas só lembrando, para cada model você terá um controller! E então você pode ter várias views que renderizam o mesmo model (exemplo acima). Aí então você programa o comportamento de cada view quando o model for atualizado.

Isso eu acho que entendi, o que ta pegando agora é como administrar as varias instancias do Model dentro do mesmo Controller

Já que tenho uma constante pra cada Controller e varias instancias de um mesmo Model (uma para cada linha da tabela) adicionadas nessa mesma constante e o que acontece é que quando mando atualizar uma instancia especifica do Model o Controller atualiza todas e isso não é desejado, já tentei identificar pelo id ou por outro atributo mas não sei como o Model vai receber esse atributo nem como ele vai comparar com os demais registrados, ou testar recebendo como parâmetro e lendo por uma Constante no Controller como os demais atributos!

Até!


Aí é que tá, você não precisa (na minha opnião, nem deve) ter várias instâncias do mesmo model. Você deve ter apenas uma instância do model e uma do controller e as views podem variar. Você está com dificuldades para programar o comportamento da sua view de pesquisa quando o model é atualizado (se não me engano você está usando uma JTable).

Pense naqueles 3 milhões de registros que você falou que queria exibir (apesar de eu acreditar que você NÃO FARÁ ISSO), imagine que além de trazer 3 milhões de registros, você terá 3 milhões de instância do mesmo model! :shock: . Se entendi bem, será um para cada linha exibida na JTable.

Como eu disse, não faça isso. Tenha apenas uma instância do model e aí você tem que achar a maneira de sua JTable funcionar como você quer. Uma boa saída por exemplo seria passar a linha da JTable a ser atualizada pelo model. Ou você pode também dar um refresh na pesquisa.

Aqui só deixo exibir (estourando) umas 200 linhas na JTable.

InSeOfKn

Agora me perdi de vez! Como eu não vou ter varias instâncias de do mesmo model?, como eu vou exibir simultaneamente o José, a Maria, o João… se eu não tiver uma instância pra José, Maria e João? o que o método critera.list() retornaria se não fosse varias instâncias do mesmo model (que com você disse são os POJOs)??

Não consigo pensar em um jeito de ter vários clientes e só uma instância guardando o nome, telefone, data de nascimento
de todos esses clientes
Até!

J

InSeOfKn:
Agora me perdi de vez! Como eu não vou ter varias instâncias de do mesmo model?, como eu vou exibir simultaneamente o José, a Maria, o João… se eu não tiver uma instância pra José, Maria e João? o que o método critera.list() retornaria se não fosse varias instâncias do mesmo model (que com você disse são os POJOs)??

Não consigo pensar em um jeito de ter vários clientes e só uma instância guardando o nome, telefone, data de nascimento
de todos esses clientes
Até!


O criteria.list() te retorna uma List (e não um model) contendo os valores retornados do banco e posteriormente você pode iterar nessa list e fazer um cast para o seu model.

Exemplo:

Cliente clienteObj;
for (Iterator i = list.iterator; i.hasNext();){
    clienteObj = (Cliente) i.next(); //Faz o cast.
    clienteModel.setNome = clienteObj.getNome(); //Modificando o model.
}

Assim você pode ter somente um model e modificá-lo sem problemas quando tiver uma list com os dados do banco.

InSeOfKn

Deixa eu ver se entendi!
Para cada tabela no banco de dados eu vou ter um Model, um Controller e algumas Views e não tem nada a ver com as class anotadas no mapiamento do hibernate

ex:

Cliente - class que o hibernate usa que representa a tabela no banco de dados

ClienteModel - model que se deve manter uma única instancia

ClienteController - controller que se deve manter uma única instancia

ClienteEditar - umas das views

ClienteVer - uma das views

Se for assim tudo bem, mas ainda não sei como preencher o meu JTable com o valor de varios clientes, alguma dica?

Até!

InSeOfKn

Outra coisa se minhas tabelas tiverem relacionamento com outras tabelas como ficaria o model?

Por exemplo, o Cliente ele tem relacionamento OneToOne com Endereço, eu teria que ter um model para endereço e cliente né? Mas como acessaria do model cliente o model endereço?

Até!

J
InSeOfKn:
Deixa eu ver se entendi! Para cada tabela no banco de dados eu vou ter um Model, um Controller e algumas Views e não tem nada a ver com as class anotadas no mapiamento do hibernate
As classes anotadas são seus models!
InSeOfKn:
Se for assim tudo bem, mas ainda não sei como preencher o meu JTable com o valor de varios clientes, alguma dica?
ObjectTableModel nela! Use o ObjectTableModel na sua JTable que ela trabalha diretamente com sua classe de negócio (seu model, ou também sua classe anotada). Se tiver dúvidas em como usar o ObjectTableModel eu posso te ajudar.
InSeOfKn:
Outra coisa se minhas tabelas tiverem relacionamento com outras tabelas como ficaria o model?

Por exemplo, o Cliente ele tem relacionamento OneToOne com Endereço, eu teria que ter um model para endereço e cliente né? Mas como acessaria do model cliente o model endereço?

Até!
Seu model ficaria com o mapeamento normal. Quando você trazer os dados do banco o hibernate te retornará uma list contendo os clientes e os endereços do relacionamento. Então é só você realizar o get ou set normalmente. Exemplo:
clienteModel.getEndereco().getRua();
Um exemplo de como ficaria o código se você usar o ObjectTableModel ao invés de enums:
@Entity  
@Inheritance(strategy=InheritanceType.JOINED)  
public class Pessoa extends AbstractModel implements Serializable {  
    private static final long serialVersionUID = 5546109411213254415L;  
  
    @Id  
    @GeneratedValue(strategy = GenerationType.AUTO)  
    @Column(name = "id_pessoa")
    @Resolvable(colName="Pessoa Id:") //Anotação para o ObjectTableModel
    private Long id;  
    @Column(unique = false, nullable = false) 
    @Resolvable(colName="Pessoa Nome:") //Anotação para o ObjectTableModel
    private String nome;  
    @Column(unique = false, nullable = true)  
    @Resolvable(colName="Telefone 1:") //Anotação para o ObjectTableModel
    private String tel_1;  
    @Column(unique = false, nullable = true)  
    @Resolvable(colName="Telefone 2:") //Anotação para o ObjectTableModel
    private String tel_2;  
    @Column(unique = false, nullable = true)  
    @Resolvable(colName="Pessoa Doc:") //Anotação para o ObjectTableModel
    private String doc;  
    @OneToOne  
    @Cascade(CascadeType.ALL)  
    @JoinColumn(name="id_endereco")  
    private Endereco endereco;
Aí na classe onde está sua table vc coloca:
AnnotationResolver resolver = new AnnotationResolver(Pessoa.class);
ObjectTableModel<Pessoa> modeloJTable = new ObjectTableModel<Pessoa>(resolver,"id,nome,tel_1,tel_2,doc");
Depois é mais simples ainda, quando você tiver com a list retornada da pesquisa que o hibernate faz é só pegar e adicionar ela ao model da sua JTable! :wink:
modeloJTable.setData(list);
jTable.setModel(modeloJTable); //Seta o model na instância da sua JTable.

Simples não? :D

InSeOfKn

Ta, ok me convencesse a usar o ObjectTableModel já até tinha baixado o projeto towel (útil como uma toalha :smiley: ) mas nem tinha testado!

Já anotei minhas classe para usar ele mas uma coisas me intriga

:arrow: Ele não quebraria o padrão MVC?
já que é o Model que vai decidir qual o nome da coluna que seria papel da view , por exemplo se eu tiver outa view só que nela o nome da coluna tenha que ser Nome em vez de Nome da Pessoa

E outra coisa terias um exemplo de Controller? se tiveres o Controller daquele Banco seria ótimo, mas pode ser qualquer Controller! acreditas ainda não sei como o Controller efetuara as mudansas em um Model especifico (que guarda José por exemplo).

Até, e obrigado novamente pela atenção!

J
InSeOfKn:
:arrow: Ele não quebraria o padrão MVC? já que é o Model que vai decidir qual o nome da coluna que seria papel da view , por exemplo se eu tiver outa view só que nela o nome da coluna tenha que ser Nome em vez de Nome da Pessoa
Podemos até dizer que sim! Mas ele simplifica bastante o trabalho por trabalhar com annotations!
InSeOfKn:
E outra coisa terias um exemplo de Controller? se tiveres o Controller daquele Banco seria ótimo, mas pode ser qualquer Controller! acreditas ainda não sei como o Controller efetuara as mudansas em um Model especifico (que guarda José por exemplo).
Claro, mas ainda falta colocar os metodos de pesquisa nele
import com.jns.util.mvc.AbstractController;
import com.jns.util.mvc.AbstractModel;
import com.jns.util.CrudActionsDAO;

/**
 *
 * @author Joyle
 */
public class BancosController extends AbstractController {

    public static final String BANCO_ID_PROPERTY = "BancoId";
    public static final String BANCO_COD_PROPERTY = "BancoCodBanco";
    public static final String BANCO_NOME_PROPERTY = "BancoNome";
    public static final String BANCO_WEBSITE_PROPERTY = "BancoWebsite";

    public boolean recordSave(CrudActionsDAO dao, AbstractModel model) {
        if (model instanceof BancosModel) {
            if (dao instanceof BancosDAO){
                return dao.recordSave(model);
            }
        }
        return false;
    }

    public boolean recordDelete(CrudActionsDAO dao, AbstractModel model) {
        if (model instanceof BancosModel) {
            if (dao instanceof BancosDAO){
                return dao.recordDelete(model);
            }
        }
        return false;
    }

    public boolean recordUpdate(CrudActionsDAO dao, AbstractModel model) {
        if (model instanceof BancosModel) {
            if (dao instanceof BancosDAO) {
                return dao.recordUpdate(model);
            }
        }
        return false;
    }
Você não vai ver um método changeNome por exemplo porque tenho outro método no AbstractController que faz a mudança pra mim de cada propriedade que quero. Assim não fico escrevendo um monte de código! O método que fiz é esse :
/**
     * Changes the model property.
     * @param propertyName The property name to be changed
     * @param newValue The new property value.
     */
    public void changePropertyValue(String propertyName, Object newValue){
        setModelProperty(propertyName, newValue);
    }
Aí pra usar ele simplesmente faço assim:
controller.changePropertyValue(BancosController.BANCO_NOME_PROPERTY, txtBancoNome.getText());
InSeOfKn:
acreditas ainda não sei como o Controller efetuara as mudansas em um Model especifico (que guarda José por exemplo).
Isso porque vc ainda tá entendendo uma List como um Model! Quando você receber a list do hibernate, você pode iterar sobre a list como falei antes e ir alterando o model de acordo com o registro selecionado na list. Entendeu? Tipo, na sua JTable você mostra uma list contento várias linhas, aí quando você selecionar uma determinada linha da sua JTable por exemplo, você pegua esses valores da linha selecionada e modifica o seu model. Se for selecionada outra linha na JTable, faz a mesma coisa, pegua os valores e modifica o model! Assim todas as views interessadas serão notificadas quando o model mudar. Eu faço assim aqui pra poder resolver isso:
private void refreshModel() {
        List list = bancoTableModel.getList(bancoTable.getSelectedRows()); //"bancoTableModel" é o meu modelo (ObjectTableModel) da JTable e "bancoTable" é minha JTable.
        BancosModel bancosObject;
        for (Iterator i = list.iterator(); i.hasNext();){
            bancosObject = (BancosModel) i.next(); //Faz o cast
            controller.changePropertyValue(BancosController.BANCO_ID_PROPERTY, bancosObject.getBancoId());
            controller.changePropertyValue(BancosController.BANCO_COD_PROPERTY, bancosObject.getBancoCodBanco());
            controller.changePropertyValue(BancosController.BANCO_NOME_PROPERTY, bancosObject.getBancoNome());
            controller.changePropertyValue(BancosController.BANCO_WEBSITE_PROPERTY, bancosObject.getBancoWebsite());
        }
    }
Aí você pode por exemplo chamar esse método no evento mouseClicked da sua JTable.
InSeOfKn

Não intendi! porque que eu modificaria o model quando selecionasse uma linha no JTable? já que o JTable é usado só para visualizar, creio que não faz sentido atualizar o model sé nada foi modificado, eu não teria que chamar changePropertyValue somente quando uma propriedade fosse alterada por exemplo no evento do botão salve na view editar. terias como me explicar melhor, quando devo chamar changePropertyValue?

Adaptando o seu controller para o meu caso e achei algo estranho que impede que código compile

return recordSave(model)

na linha 19 pelo código do post acima

com posso retornar recordSave se ele não retorna boolean??

Para continuar adaptando coloquei um return true; em baixo mas achei melhor avisar pois esse return true não garante que tenha salvo (pode ter entrado no catch no BancoDAO)

Até! quando terminar de adaptar volto a postar!

J

Não intendi! porque que eu modificaria o model quando selecionasse uma linha no JTable? já que o JTable é usado só para visualizar, creio que não faz sentido atualizar o model sé nada foi modificado, eu não teria que chamar changePropertyValue somente quando uma propriedade fosse alterada por exemplo no evento do botão salve na view editar. terias como me explicar melhor, quando devo chamar changePropertyValue?
É porque quando ele clica em um registro na JTable eu já levo o registro pra outras views (isso acontece quando modifico o model) e em uma view ele edita o registro. Se a view de edição não estiver aberta, ele (o usuário) pode abrir a view de edição e selecionar o registro a ser editado na JTable que quando a JTable modificar o model o registro aparecerá na janela de edição e assim poderá ser editado. Entendeu?

InSeOfKn:

Adaptando o seu controller para o meu caso e achei algo estranho que impede que código compile

return recordSave(model)

na linha 19 pelo código do post acima

com posso retornar recordSave se ele não retorna boolean??

Para continuar adaptando coloquei um return true; em baixo mas achei melhor avisar pois esse return true não garante que tenha salvo (pode ter entrado no catch no BancoDAO)

Até! quando terminar de adaptar volto a postar!


No caso o meu DAO é responsável por verificar se o registro foi realmente gravado ou não e assim o DAO retorna um valor booleano que o controller retorna automaticamente no return recordSave(model)

De qualquer forma já fiz várias mudanças no meu código aqui desde quando postei os códigos de exemplo.
Também estou criando o que estou chamando de MVCManager. Ele é um gerenciador que to criando para organizar a criação de controllers e models para as views interessadas no mesmo controller e no mesmo model.
Quando tiver uma versão mais estável posto aqui pra vc ver.

InSeOfKn

Tá ok, criei o método refreshModel() na minha view Ver que é chamando sempre que se clica no botão editar que abre a View Editar mas como é que la na view editar eu pegaria esse os dados pra deixar autopreenchido e como de la eu notificaria as demais views que os dados mudaram?

antes eu mandava a própria linha como parâmetro no construtor, deveria continuar com isso??

Mais uma coisa onde eu instancio meus DAOs??

Até!

J

InSeOfKn:
Tá ok, criei o método refreshModel() na minha view Ver que é chamando sempre que se clica no botão editar que abre a View Editar mas como é que la na view editar eu pegaria esse os dados pra deixar autopreenchido e como de la eu notificaria as demais views que os dados mudaram?

antes eu mandava a própria linha como parâmetro no construtor, deveria continuar com isso??

Mais uma coisa onde eu instancio meus DAOs??

Até!


Opa… desculpa a demora em responder! Não estava tendo muito tempo para analisar a questão…

Aqui eu chamo o refreshModel sempre que clico em uma linha na JTable de pesquisa, no seu caso ela está na sua view Ver. Então toda vez que você clicar em uma linha na JTable que está na sua view Ver você chama o refreshModel que levará os dados para o model e que o model por sua vez irá notificar as views interessadas (desde que as views interessadas estejam registradas no mesmo controller e utilizem o mesmo model! :wink: ).
Assim os dados serão carregados para a sua view Editar sempre que você clicar em uma linha na JTable!

Se você fizer como citado acima não haverá necessidade de mandar a linha pelo construtor.

Eu levo uma levo uma instância para o método no controller, mas você pode instanciá-lo direto no controller também.

Tudo na verdade depende de como você está projetando seu software. Um grande problema com os desenvolvedores em projetos pessoais é que simplesmente se senta em frente a um computador e linhas e mais linhas de código são escritas sem se quer se pensar na estrutura e padrões que serão adotados para o software. Isso, obviamente trará grandes dores de cabeça no futuro com novas implementações e manutenção no sistema.

Antes de começar a programar, projete como seu sistema irá funcionar, como ele irá se comportar e quais serão os padrões que serão utilizados no seu desenvolvimento. Quando começar a desenvolver, você terá menos dificuldades para aplicar os conceitos. E apesar de ter que gastar um tempinho a mais pensando e projetando seu sistema, você irá sentir a diferença na hora de programar, além de fazer um sistema bem estruturado e sem muitos dos problemas que você teria no futuro.

InSeOfKn

Sem pressa, só em você esta usando o seu apertado tempo para me ajudar já sou eternamente grato!

joyle:
Aqui eu chamo o refreshModel sempre que clico em uma linha na JTable de pesquisa, no seu caso ela está na sua view Ver. Então toda vez que você clicar em uma linha na JTable que está na sua view Ver você chama o refreshModel que levará os dados para o model e que o model por sua vez irá notificar as views interessadas (desde que as views interessadas estejam registradas no mesmo controller e utilizem o mesmo model! ).
Assim os dados serão carregados para a sua view Editar sempre que você clicar em uma linha na JTable!

Problema que possivelmente eu teria com isso seria preder a possibilidade de interagir com o JTable com o teclado, para evitar isso acho que não teria problemas em chamar o refreshModel na ação do Botão editar já que ele abre a única View que tem interesse nos dados da view de pesquisa.

Na verdade esse é o meu primeiro projeto que eu faço por contra própria, tenho ele em mente desdo ano retrasado mas me considerava sem conhecimento par faze-lo, até que ano passado resolvi começar, dai foi aparecendo Hibernate, DAOs, MVC entre outras coisas para estudar, fugindo totalmente do que eu tinha pensado, que era só Views que acessavam diretamente o banco com JDBC puro (imagina a bagunça :smiley: ), forra esse projeto só os trabalhos da disciplina de logica de programação no técnico, e alguns joguinhos e calculadoras (nada que não se faz em 1 ou 2 dia).
Então essa dica é muito boa para os meus próximos projetos, pois agora sinto que me falta experiencia para aperfeiçoar minha logica que não é muito ampla e entender como funciona o MVC (o que esta difícil pois em cada lugar que eu leio falam uma coisa diferente).

Mas para min ver se entendi da uma olhada

O Controller chama o DAO que devolve uma lista de Model e o Controller se encarrega de repassar essa lista para a View de pesquisa

A View de pesquisa chama o método refreshModel que envia os dados da linha selecionada para um Model que fica guardado no Controller

A View de edição pucha esses dados do Model guardado no Controller e autocompleta os campos e o botão salvar dessa View altera os dados desse Model e logo em seguida chama um método do Controller para persistir esses dados

O Model ao ser alterado notifica o Controller que por sua vez notifica as Views que se atualizam reiniciando o ciclo!

É isso?

Até, amanha tento colocar em pratica o que foi dito acima!

J

Porque perderia essa possibilidade de interação com o teclado?

InSeOfKn:
Mas para min ver se entendi da uma olhada

O Controller chama o DAO que devolve uma lista de Model e o Controller se encarrega de repassar essa lista para a View de pesquisa

A View de pesquisa chama o método refreshModel que envia os dados da linha selecionada para um Model que fica guardado no Controller

A View de edição pucha esses dados do Model guardado no Controller e autocompleta os campos e o botão salvar dessa View altera os dados desse Model e logo em seguida chama um método do Controller para persistir esses dados

O Model ao ser alterado notifica o Controller que por sua vez notifica as Views que se atualizam reiniciando o ciclo!

É isso?


É por aí mas,

Quem notifica as views é o model! O método firePropertyChange é quem faz isso!

InSeOfKn

Pois se só quando clicasse na linha mandasse os dados ao selecionar uma linha com as setas do teclado e clicar em editar a view editar estaria editando a ultima linha clicada não a linha selecionada, concordas?

Que bom! To terminando de implementar aqui quando acabar eu posto!

joyle:
InSeOfKn:
O Model ao ser alterado notifica o Controller que por sua vez notifica as Views que se atualizam reiniciando o ciclo!
Quem notifica as views é o model! O método firePropertyChange é quem faz isso!

Sim! acho que me precipitei em dizer isso, quando na verdade quis dizer que é o Controller que diz que aquela view monitora aquele Model e aquele Model deve notificar aquelas Views

Até!

J

Ué, é só atualizar os dados com o evento keyPressed ou keyReleased da JTable ou como você quiser que o model seja atualizado quando pressionar as setas! :wink:
Aqui eu uso o evento keyReleased.

Legal saber que está indo bem. Qualquer dúvida posta aí, se eu não puder ajudar, a comunidade é bem grande e com certeza poderá! :slight_smile:

Criado 13 de janeiro de 2011
Ultima resposta 8 de fev. de 2011
Respostas 55
Participantes 5