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]
[quote=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][/quote]
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.
[code]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 Session - If session not null.
-
@return Null - If session is null.
*/
protected Session getSession(){
if (session != null)
return session;
return null;
}
/**
- Return the Transaction
-
@return Transaction - If transaction not null.
-
@return Null - 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;
}
}
[/code]
Algumas coisas anotei em portugues e outras em inglês mesmo. Depois tenho que mudar isso.
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é!
Olha eu aqui incomodando de novo
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?
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?
Instancie seu model e dê um controller.addModel(model).
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?
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) 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é!
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.
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 …
[quote=joyle]
Muito pelo contrário. O seu controller sabe exatamente onde entragar as cartas, por isso você registra as views e os models.[/quote]
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!
[quote=InSeOfKn][quote=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.
[/quote]
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 …[/quote]
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.
[quote=InSeOfKn]
[quote=joyle]
Muito pelo contrário. O seu controller sabe exatamente onde entragar as cartas, por isso você registra as views e os models.[/quote]
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! [/quote]
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?
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:
Dá uma olhada nesse tópico aqui : http://www.guj.com.br/java/129277-perguntas-sobre-mvc-desktop-existe-solucao–mvpmvc-webobserver-e-exceptions
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
Até estou aperfeiçoando aqui o que consegui fazer e já posto!
[quote=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é?
[/quote]
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?
Como prometido estou aqui postando o que fiz!
Modelo:
Cliente:
[code]@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;
}
}[/code]
Pessoa:
[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")
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;
}
}[/code]
Controller:
ClienteController:
[code]
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);
}
}[/code]
AbstractController:
[code]
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) {
}
}
}
}[/code]
View:
abstractViewPane:
[code]public abstract class AbstractViewPane 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);
}
}[/code]
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é
[quote=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?[/quote]
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
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.
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!
[quote=joyle]
Vou te mostrar como faço aqui e quando tiver mais tempo posto umas classes de exemplo, se vc quiser claro.[/quote]
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é!
Que isso, quando preciso de ajuda o pessoal também faz o mesmo!
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é!