Relacionamento Muito para Muitos
Gostaria de saber como eu trato um relacionamento muito para muitos, do tipo tenho uma tabela Aluno, uma tabela Materias, um aluno pode ter muitas matérias e uma matéria pode ter muitos alunos...
Quero saber como faço esse tratamento na prática com Orientação ao Objeto, no caso eu teria uma classe chamada Aluno e outra Materia, se for com um atributo do tipo List<Materia> na classe Aluno por exemplo, como eu faço o tratamento no momento que por exemplo eu excluir, selecionar, editar ou incluir uma matéria já que estou fazendo o tratamento através de List.
Como eu faço esse tratamento ? Pois no O.O. seria errado eu construir uma classe apenas para esse relacionamento. Gostaria de um exemplo na prática para esse problema.
Vinicius Climaco
Curtidas 0
Respostas
Luiz Maia
26/12/2008
Vinícius,
O problema que enfrenta não tem uma resposta que seje a "fórmula ideal", afinal esse e um grande paradigma, visto que o Banco é Relacional e o projeto O.O. Para isso existem diversos Patterns e esse assunto e muito discutido.
No seu exemplo, a classe Aluno deveria ter uma propriedade chamada Materia, do tipo MateriaCollection. MateriaCollection, por sua vez, estende List<Materia> - ou seja, é uma lista genérica de matérias.
No caso de relacionamentos n x n (por exemplo, produtos e fornecedores), a classe Produto teria uma propriedade Fornecedores e a classe Fornecedor teria uma propriedade Produtos, ambas retornando uma coleção. Ou seja, repare que do ponto de vista da orientação a objetos não faz diferença como os relacionamentos estão representados no banco de dados.
Espero ter ajudado.
Qualquer coisa estou a disposição de vc.
Aguardo seu feedback
Abraços
Luiz Maia
GOSTEI 0
Vinicius Climaco
26/12/2008
Sim... mas no caso eu gostaria de saber como eu consigo fazer esse mapeamento de estar sempre atualizado, digamos eu tenho um List<Materia> uma propriedade lá na Classe Aluno na qual faço referência a Classe Materia.
Gostaria de um exemplo desse mapeamento, com uma funcionalidade, digamos o editar, deletar, inserir materia, seria o caso de eu mecher diretamente com a Classe de Negócios de Materia certo ? No caso do atributo List<Materia> da classe Aluno eu faria apenas o comando Select (Seleção de matérias existentes nos alunos) ?
Poderia enviar um exemplo desse tipo para meu e-mail viniclima@hotmail.com, se tiver uma imagem da DER com a imagem do Diagrama de Classe facilitaria muito.
GOSTEI 0
Luiz Maia
26/12/2008
Vinícius,
Se você pretente gerenciar dados de materias, vc irá manipular somente a classe materia na camada de negócios mesmo.
No caso de querer recuperar as materias relacionadas aos alunos, como você terá a instancia da classe Materias dentro da classe aluno, deve deve apenas varer estes registros para obter as materias relacionadas ao aluno em questão.
Dê uma olhada no seguinte video:
https://www.devmedia.com.br/articles/viewcomp.asp?comp=7702
Caso precise de acesso, me diga.
Abraços
Luiz Maia
GOSTEI 0
Luiz Maia
26/12/2008
Vinicius, segue um exemplo do Diagrama de classes, como solicitou:
Repare que o relacionamento das classes Usuario e Materias é N:N, no que resultou na classe Emprestimo, com os metodos necessarios.
Abraços
Luiz Maia
GOSTEI 0
Vinicius Climaco
26/12/2008
Sim... digamos na prática no meu banco de dados eu teri uma tabela Usuario, Materiais e Usuario_Materiais (que seria o relacionamento muito-para-muito) até aqui ok... mas e na classe como seria esse relacionamento ? Como eu represento na prática na classe Usuario que eu tenho N tipos de materiais e outra com os respectivos nomes e id´s referentes ao mesmos...
Por exemplo quero recuperar um usuario com todos os dados gerais dele, tudo de uma vez, por exemplo nome, senha, telefone, celular, idade, etc, inclusive os materiais que esse usuario tem... como isso seria feito ? eu teria um atributo List no Usuario ? Como seria o preenchimento desse List lá na camada de Dados na hora do que eu fosse preencher a Classe Usuario na prática.
GOSTEI 0
Luiz Maia
26/12/2008
Vinicius,
Segue a representação:
O relacionamento na classe seria da seguinte forma:
1 - Vc deve criar um atributo List no Aluno para as materias pertinentes a ele.
2 - O preenchimento do List de materias seria exatamente na hora da chamada da classe Aluno.
3 - Se vc esta usando Link, o Linq requer que vc defina a tabela ponte como uma entidade. Não tem outro jeito.
Segue o codigo:
public class Aluno{
// Alguns membros privados vc coloca aqui
// ...
public Aluno() {}
// Propriedades do objeto Aluno public String Codigo { get {return _codigo;} set {_codigo = value;}}
public String Nome { get {return _nome;} set {_nome = value;}}
// 1-n propriedade do relacionamento public ArrayList Aluno_Materia
{ get {return _aluno_materia;} set {_aluno_materia= value;}}
}
public class Aluno_Materia{
// membros privados e etc
// ...
public Aluno_Materia() {}
// Propriedades do objeto Aluno_Materia public String AlunoId { get {return _alunoId;} set {_alunoId= value;}}
public String MateriaId { get {return _materiaId;} set {_materiaId = value;}}
// n-1 Propriedades dos relacionamentos public Aluno Aluno { get {return _aluno;} set {_aluno = value;}}
public Materia Materia { get {return _materia;} set {_materia = value;}}
} public class Materia{
// ...
public Materia() {}
// Propriedades do objeto Materia public String Codigo { get {return _codigo;} set {_codigo = value;}}
public String Nome { get {return _nome;} set {_nome = value;}}
// relacionamento um para um public ArrayList Aluno_Materia
{ get {return _aluno_materia;} set {_aluno_materia= value;}}
} Como vc pode ver acima, Aluno e Materia, ambos mantem a coleção Aluno_Materia como propriedade. Agora, se Aluno_Materia nao ter nenhum atributo alem das PKs, nos poderiamos simplesmente ter colocado a coleção de Alunos em Materias e a coleção de Materias em Alunos. Mas para manter a conscistencia, sempre devemos colocar a coleção dos objetos mapeados na Classe da tabela "ponte". Desta forma, se vc decidir adicionar atributos na tabela ponte, não perderá a sua consistencia e não precisará refazer seu Objectc Model. Agora o código da camada de persistencia, para recuperação do Aluno com todos os dados seguindo o que vc me solicitou: public class Aluno_MateriaFactory : DbObject, IAluno_MateriaFactoryFactory {
// ...
public Aluno_MateriaFactoryFactory() {} public ArrayList ProcurarComMaterias (String alunoId)
{
try
{
String sql = "SELECT codigo, am.materia, .... FROM materia INNER JOIN aluno_materia am ON m.codigo = am.materia
WHERE codigo = ?";
ArrayList ctList = new ArrayList(); PrepareSql(sql);
BeginTransaction();
AddCmdParameter("@alunoId", EDataType.eString, alunoId, EParamDirection.eInput);
ExecuteReader();
while (Read())
{
Aluno_MAteria am = new Aluno_MAteria();
FillAluno_MAteria(am); // copia os registros do Reader para Aluno_MAteria Materia mat = new Materia();
FillMateria (mat); // copia regsitros do Reader para Materia am.Materia = mat; // a referencia de am agora é de (n-1) para Materia
amList.Add(am);
}
ReleaseReader();
CommitTransaction();
ReleaseCommand(); return amList;
}
catch (Exception ex)
{
Rollback();
throw ex;
} Acima é a representação de todo o codigo que precisa. Qualquer coisa estou a disposição. Abraços Vinicius Att, Luiz Maia
// Alguns membros privados vc coloca aqui
// ...
public Aluno() {}
// Propriedades do objeto Aluno public String Codigo { get {return _codigo;} set {_codigo = value;}}
public String Nome { get {return _nome;} set {_nome = value;}}
// 1-n propriedade do relacionamento public ArrayList Aluno_Materia
{ get {return _aluno_materia;} set {_aluno_materia= value;}}
}
public class Aluno_Materia{
// membros privados e etc
// ...
public Aluno_Materia() {}
// Propriedades do objeto Aluno_Materia public String AlunoId { get {return _alunoId;} set {_alunoId= value;}}
public String MateriaId { get {return _materiaId;} set {_materiaId = value;}}
// n-1 Propriedades dos relacionamentos public Aluno Aluno { get {return _aluno;} set {_aluno = value;}}
public Materia Materia { get {return _materia;} set {_materia = value;}}
} public class Materia{
// ...
public Materia() {}
// Propriedades do objeto Materia public String Codigo { get {return _codigo;} set {_codigo = value;}}
public String Nome { get {return _nome;} set {_nome = value;}}
// relacionamento um para um public ArrayList Aluno_Materia
{ get {return _aluno_materia;} set {_aluno_materia= value;}}
} Como vc pode ver acima, Aluno e Materia, ambos mantem a coleção Aluno_Materia como propriedade. Agora, se Aluno_Materia nao ter nenhum atributo alem das PKs, nos poderiamos simplesmente ter colocado a coleção de Alunos em Materias e a coleção de Materias em Alunos. Mas para manter a conscistencia, sempre devemos colocar a coleção dos objetos mapeados na Classe da tabela "ponte". Desta forma, se vc decidir adicionar atributos na tabela ponte, não perderá a sua consistencia e não precisará refazer seu Objectc Model. Agora o código da camada de persistencia, para recuperação do Aluno com todos os dados seguindo o que vc me solicitou: public class Aluno_MateriaFactory : DbObject, IAluno_MateriaFactoryFactory {
// ...
public Aluno_MateriaFactoryFactory() {} public ArrayList ProcurarComMaterias (String alunoId)
{
try
{
String sql = "SELECT codigo, am.materia, .... FROM materia INNER JOIN aluno_materia am ON m.codigo = am.materia
WHERE codigo = ?";
ArrayList ctList = new ArrayList(); PrepareSql(sql);
BeginTransaction();
AddCmdParameter("@alunoId", EDataType.eString, alunoId, EParamDirection.eInput);
ExecuteReader();
while (Read())
{
Aluno_MAteria am = new Aluno_MAteria();
FillAluno_MAteria(am); // copia os registros do Reader para Aluno_MAteria Materia mat = new Materia();
FillMateria (mat); // copia regsitros do Reader para Materia am.Materia = mat; // a referencia de am agora é de (n-1) para Materia
amList.Add(am);
}
ReleaseReader();
CommitTransaction();
ReleaseCommand(); return amList;
}
catch (Exception ex)
{
Rollback();
throw ex;
} Acima é a representação de todo o codigo que precisa. Qualquer coisa estou a disposição. Abraços Vinicius Att, Luiz Maia
GOSTEI 0
Vinicius Climaco
26/12/2008
Luiz é correto criar essa classe de relacionamento Aluno_Materia, pois já me informaram que este tipo de relacionamento esta errado, que o correto é ter um atributo do tipo List para suprir isso e apenas isso.
Então vamos lá, na convenção de O.O. é correto criar dessa forma ?
GOSTEI 0
Vinicius Climaco
26/12/2008
Respondendo não uso o Linq, utilizo o VS 2008, porém não curto muito a utilização do Linq por enquanto.
GOSTEI 0
Luiz Maia
26/12/2008
Vinicius,
Como eu disse acima, caso vc tenha necessidades de mais atributos na classe Aluno_Materia que nao sejam as PKs, vc nao precisa desta classe, apenas os atributos List nas outras, mas é uma boa pratica usa-la, pois futuramente não será necessário remodelar toda estrutura no caso de inserir um atributo nela.
No DER vc tem que tê-la, mas na OO não precisa a não pela exceção acima.
Abraços
Luiz Maia
GOSTEI 0
Vinicius Climaco
26/12/2008
Luiz valeu mesmo pelas dicas, desde já quero dizer que o atendimento tem sido DEZ e vou recomendar a consultoria ao pessoal que conheço. Muito bom mesmo.
Vou testar esse formato ai que você disse e posto até segunda (dia 5) o resultado.
Abração e mais uma vez parabéns.
GOSTEI 0
Luiz Maia
26/12/2008
Valeu pela força Vinicius.
Precisando, é só entrar em contato conosco, será um prazer atendê-lo novamente.
Abraços
Luiz Maia
GOSTEI 0