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

[quote=InSeOfKn][quote=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.
[/quote]

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é![/quote]
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.

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é!

[quote=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é![/quote]
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.

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é!

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é!

[quote=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
[/quote]
As classes anotadas são seus models!

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.

[quote=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é! [/quote]
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:

[code]@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;  

[/code]

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? :smiley:

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!

[quote=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
[/quote]
Podemos até dizer que sim! Mas ele simplifica bastante o trabalho por trabalhar com annotations!

Claro, mas ainda falta colocar os metodos de pesquisa nele

[code]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;
    }[/code]

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());

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.

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!

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?[/quote]
É 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?

[quote=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![/quote]
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.

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é!

[quote=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é![/quote]
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.

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

[quote=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! [/quote]

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!

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

[quote=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?
[/quote]
É por aí mas,

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

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!

[quote=joyle][quote=InSeOfKn]O Model ao ser alterado notifica o Controller que por sua vez notifica as Views que se atualizam reiniciando o ciclo!
[/quote]Quem notifica as views é o model! O método firePropertyChange é quem faz isso![/quote]
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é!

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: