Modelagem de hierarquias em sistema Grails
08/10/2011 19:19
1
Olá, pessoal!

Estou com uma dúvida em como vou tratar a situação abaixo! Gostaria de saber qual seria a melhor solução (ou a mais elegante :-) ).

É o seguinte:

Meu sistema tem uma entidade "Usuario". No CRUD desse usuário existe um atributo de nome "cargo". Os cargos possíveis para esse usuário são 3: "gerente regional", "gerente de divisão", "gerente de setor". Eu criei, portanto, uma entidade para cada um desses atributos, ou seja: Uma entidade "Setor" (que pertence a uma "Divisão", ex: setor 134 - divisão Rio de Janeiro), uma entidade "Divisão" (que pertence a uma "Região", ex: divisão Rio de Janeiro - região Sudeste) e uma entidade Região.
De acordo com o requisito que foi levantado junto ao cliente, com base na escolha do atributo cargo no cadastro de Usuario, ele quer associar o mesmo à um setor, à uma divisão (caso ele seja um "gerente de divisão") ou à uma região (caso ele seja um "gerente regional").
Como solução, apresentei que o melhor a fazer é ter essa associação diretamente nas entidades, por exemplo: O cara acabou de cadastrar um novo Usuário. Se esse usuário é um gerente de setor, em seguida ele deve ir no CRUD de "Setor" e associar o usuário que ele acabou de criar ao setor que ele deseja. Mas como as pessoas que vão fazer manutenção desse sistema não querem fazer esse processo em 2 telas diferentes, ele solicitou se não tem uma forma de fazê-lo dinâmicamente, direto no CRUD do Usuario. A minha dúvida seria como posso modelar esse processo da melhor forma possível? Vocês já passaram por situação semelhante?
Muito obrigado!
Tags: CRUD, modelagem, entidade, relacionamento, GORM


2
Oi Carlos,

neste caso, basta que você coloque tudo na mesma página. Se os setores expostos variarem de acordo com o tipo de cargo, basta que você implemente alguma coisa com ajax, que seja disparado pelo evento onchange de um select (caso seja o que você esteja usando).

Em seguida, dentro do seu próprio controlador é definida qual a regra de persistência que você vai adotar e ai, xuxu beleza, tá pronto. O que me diz?


0
Olá, Kico.

Na verdade, o atributo varia de acordo com o cargo escolhido. Se eu escolher um determinado cargo, ele precisa me disponibilizar uma listagem de atributos da classe em questão (Regiao, Divisao ou Setor).
Resumidamente, minha modelagem ficou assim:

class Usuario{
String nome
Cargo cargo
}
-----------
class Regiao{
String nome
Usuario usuario
}
-----------
class Divisao{
String nome
Regiao regiao
Usuario usuario
}
-----------
class Setor{
String nome
Divisao divisao
Usuario usuario
}


A minha duvida é:
1 - Essa modelagem é a mais apropriada para essa situação?
2 - Como vou inserir os elementos de outras classes no CRUD Usuario?

A questão do Ajax já sabia que iria precisar implementar para viabilizar essa seleção dinamica dos cargos... Mas minha dúvida maior é como vou implementar essa associação. Uma dúvida teórica mesmo... :-(

Obrigado!
08/10/2011 21:44


1
Oi Carlos,

Talvez o atributo usuario não devesse estar em Regiao, não?


2
Olá Carlos,
Se eu entendi corretamente, a relação seria a seguinte:
Setor one to one Divisão one to one Região

Acho que o mais fácil/simples seria o usuário ter todos os atributos. É incorreto colocar o usuário em Entidades como Regiao, Divisao e Setor, pois elas podem ser utilizadas em outras partes do sistema que não têm a ver com o usuário. O usuário que pertence a uma Região e não uma Região que pertence ao usuário.

class Usuario{
String nome
Cargo cargo
Regiao regiao
Divisao divisao
Setor setor
}
-----------
class Regiao{
String nome
}
-----------
class Divisao{
String nome
Regiao regiao
}
-----------
class Setor{
String nome
Divisao divisao
}

Poderia também ser um auto-relacionamento do tipo:

class Unidade {
String nome
Unidade unidadePai
}

class Usuario {
String nome
Unidade unidade
}

Se o kra tiver um Setor, então a árvore vai ter três nós usuario.unidade(Setor).unidadePai(Divisao).unidadePai(Regiao). Ou seja, uma região nunca terá pai, uma Divisão terá 1 pai (Regiao) e um Setor terá dois pais (Regiao, Divisao).

Quanto a saber o que carregar (Setor, Divisao ou Regiao) quando um cargo for escolhido você pode ter uma lógica fixa no controller, se os cargos não mudarem quase nunca, mas mesmo assim não é uma boa prática.
Se eles tiverem chance de mudar, talvez colocar um nível no Cargo para saber o quão profundo ele irá buscar na árvore Região->Divisão->Setor:
class Cargo {
String nome
int nivel
}
Caso for nível 0 carrega somente Região, nível 1, carrega Divisão e assim por diante...

Para ficar tudo no mesmo CRUD tem que utilizar ajax, seguindo o que Kico mencionou mais acima.

Esta foi a solução que me veio a cabeça agora, espero que ajude, e caso tenha coisa errada me corrijam por favor.

Valeu!
08/10/2011 22:31


0
Olá, André.

Explicando melhor:

1 - Sobre a modelagem do sistema, Região, Divisão e Setor só podem estar associados à um único usuário. Por isso havia colocado o usuário nas entidades de Região, Divisão e Setor. E elas não serão utilizadas em outras partes do sistema. Apenas para definir "qual usuário toma conta do que". Mas acho q vc tem razão quando diz que isso seria incorreto...

2 - Os cargos não vão mudar. Essa regra se aplica apenas à esses 3 cargos: "Gerente Regional", "Gerente de Divisão" e "Gerente de Setor". O que facilita :-)

Achei sua idéia de criar uma única entidade com base em auto-relacionamento muito interessante! Mas acho que talvez teria dificuldades em implementar essa busca por nós. Conhece algum link sobre o assunto? De qualquer forma vou precisar ter uma lógica no meu controller para essa operação. Dependendo da complexidade, posso implementar em um service...

Tenho apenas mais uma dúvida: Quando o cara associar uma divisão à um usuário na hora de cadastrar o mesmo e já existir um usuário para àquela divisão, qual a melhor forma de implementar isso? O que eu faço com o usuário anterior? Ou bloqueio a ação e informo que já existe uma associação para àquela divisão?

Mais uma vez obrigado ao André e ao Kico... Vcs estão me ajudando bastante!!

Abraços!
09/10/2011 10:19


1
Carlos,
Infelizmente não tenho nenhum link sobre o assunto do auto-relacionamento... Mas acho que é um assunto comum e com certeza você encontrará uma solução.

Quanto a sua dúvida, acho melhor você bloquear a ação e informar que já existe a associação, ou então, se houver realmente a necessidade de sobrescrever/remover a permissão dos usuários envolvidos, informar que já existe a associação e perguntar se ele realmente gostaria de sobrescrevê-la.

Fico feliz em poder ajudar!
Um abraço!
09/10/2011 14:22


0
André,

Quanto à informar ao administrador sobre a alteração tudo bem... A minha dúvida é como saber que um usuário já está associado à uma região, divisão ou setor se eu não tiver um atributo do tipo "Usuario" nessas entidades?

A meu problema é exatamente em como estabelecer essa integridade.

Obrigado!
09/10/2011 15:07


1
Carlos,

Você não terá o usuários nas entidades, mas terá as entidades no usuário.
Ex: encontrar se já existe um usuário cadastrado para uma região: buscar na tabela de usuários se já existe um usuário associado para aquela região.

Usuario.withCriteria {
eq('regiao', regiao) //Filtra pela região que vc quer buscar
}

No caso de uma edição, você terá que buscar pela região, mas além disso deve verificar se o usuário associado a esta região é diferente do usuário que está sendo editado:

Usuario.withCriteria {
eq('regiao', regiao) //Filtra pela região que vc quer buscar
ne('usuario', usuario) //Verifica se existe outro usuário já associado à região
}

Isso evita com que o conflito ocorra com o próprio usuário sendo editado.

Seria isto?
09/10/2011 16:11


0
Muito obrigado, André!

Estou trabalhando nas suas dicas! Qualquer novidade eu posto aqui!

Abraços!
17/10/2011 19:17



Ainda não faz parte da comunidade???

Para se registrar, clique aqui.


Aprenda Groovy e Grails com a Formação itexto!

Newsletter Semana Groovy

Assinar

Envie seu link!


Livro de Grails


/dev/All

Os melhores blogs de TI (e em português) em um único lugar!

 
Creative Commons
RSS Grails Brasil é mantido por itexto Consultoria.
Em caso de problemas contacte Henrique Lobo Weissmann (Kico) por e-mail: kico@itexto.com.br
Todo o conteúdo presente neste site adota o Creative Commons como licença padrão.
Ver: 4.14.0
itexto