Oi pessoal,
primeiro queria divulgar o forum do GrailsBrasil ( www.grailsbrasil.com ). Um ótimo espaço para os brazucas, que cada vez mais descobrem e se encantam com o Grails.
Em seguida, queria falar, com certo atraso, da tão esperada Release 1.0 do Grails, que na verdade já está na 1.0.1. Isso é uma grande notícia.
Por último, a razão deste post....
O Grails 1.0.1 possui o GORM DSL, que oferece grande facilidade para controlar detalhes do mapeamento objeto relacional dos objetos de domínio. Ao migrar uma aplicação do grails 0.6 para o 1.0.1, quis alterar alguns detalhes do mapeamento, já que agoraeu conseguiria isso sem precisar apelar para mapeamento Hibernate com XML.
O problema que eu queria resolver era:
Digamos que eu tenha uma classe Usuario e outra Privilegio, com um relacionamento many-to-many entre elas. Logo teremos:
class Usuario {
String nome
static hasMany = [privilegios:Privilegio]
}
class Privilegio {
String nome
static hasMany = [usuarios:Usuario]
static belongsTo = Usuario
}
Com as classes acima, o grails gera as seguintes tabelas:
usuario
id
nome
privilegio
id
nome
usuario_priv
usuarios_id (que é uma FK para privilegio.id)
privilegios_id (que é uma FK para usuario.id)
É isso mesmo: o campo usuarios_id é uma chave estrangeira para o id da tabela privilegio; e o campo privilegios_id é uma chave estrangeira para o id da tabela usuario. A explicação pra isso está aqui (vejam o comentário do Graeme).Eu não sei quanto a vocês, mas pra mim isso soa muito estranho. Mas é assim mesmo que o grails gera por padrão. A forma que eu gosto de trabalhar é com campos no singular e com o nome do campo da chave estangeira condizente com o nome da tabela de referência:
usuario_priv.usuario_id = usuario.id
usuario_priv.privilegio_id = privilegio.id
Para isso, então, eu antigamente teria que fazer o mapemanto com XML do hibernate (já fiz vários para outras aplicações com grails). Mas agora na versão atual posso fazer o que quero com o GORM DSL. E é isso que quero mostrar, pois há um detalhe que precisei fazer alguns testes até entender o comportamento do Grails com essa DSL. Vamos lá...
class Usuario {
String nome
static hasMany = [privilegios:Privilegio]
static mapping = {
privilegios column:'usuario_id', joinTable:'usuario_priv'
}
}
class Privilegio {
String priv
static hasMany = [usuarios:Usuario]
static belongsTo = Usuario
static mapping = {
usuarios column:'privilegio_id', joinTable:'usuario_priv'
}
}
O que eu acho curioso e anti-intuitivo no código acima, é que numa primeira tentativa eu coloquei:
Mas isso acabou sendo errado. Na verdade temos que colocar como nome da coluna (para ter o resultado que eu esperava), o nome da classe em que me encontro, e não o nome do atributo de relacionamento. Em fim: o correto é o código acima completo das classe Usuario e Privilegio, e não o código acima com fundo avermelhado.class Usuario {
static mapping = {
privilegios column:'privilegio_id', joinTable:'usuario_priv'
}
}
Fiz questão de colocar isso aqui, pois a documentação não me parece muito clara quanto a isso. (talvez eu é que tenha entendido errado a documentação, sei lá....em fim....tá aí pra quem precisar deste detalhe).
Abcs
Felipe
4 comentários:
class Privilegio {
String priv
static hasMany = [usuarios:Usuario]
static belongsTo = Usuario
static mapping = {
usuarios column:'privilegio_id', joinTable:'usuario_priv'
}
}
Não sei se foi isso que vc quis dizer, mas eu entendo que, na verdade, o que temos que colocar no mapping, é o nome da Collection utilizada no hasMany. Assim, caso exista outro hasMany, o GORM consegue saber "de qual relacionamento se trata". Nesse caso usuarios.
Parabéns pelo Blog!
Olá Lucas,
na verdade, não foi esse o foco. O foco é no mundo relacional, e não nos atributos dos objetos. O que quis mostrar é que na classe Privilegio, por exemplo, o mapping de usuarios (como vc colocou em bold), tem como valor do column o campo privilegio_id, e nao usuario_id, como eu acharia mais natural de pensar. Só isso. Acho que ao fazer o mapping rapidamente, algumas pessoas poderiam fazer "usuarios column:'usuario_id'" , ao invés da forma correta que é "usuarios column:'privilegio_id'". Abraços e obrigado pelo comentário.
Parabens pelo blog, já me ajudou mt.. tb achei pouco intuitivo a maneira como o gorm mapeia na base de dados.. mas de qq forma funciona da maneira que seria esperada pelos testes que fiz, mas o meu problema surge quando tento criar as views para um relacionamento deste tipo.. sera que voce sabe de algum link pra um exemplo simples e funcional completo com views para este tipo de relacionamento.. (de 1-M tem um montao, e todo mundo diz pra procurar o M-M noutro sítio.. onde?! nenhum tem um exemplo completo..)
Abraços
Olá Cris
o Grails não gera as views quando o relacionamento é many-to-many. Um exemplo que gosto, e acho que soluciona bem este caso, é a solução que o Matt Raible usa numa nova aplicação gerada pelo AppFuse.
Dê uma olhada aqui:
http://demo.appfuse.org/appfuse-spring/login.jsp
Entre com login admin e senha admin.
Depois, no menu Administração, acesse Visualizar Usuários. Em seguida clique no botão Adicionar para ir para o formulário de criação de novo usuário. Neste formulário, há uma solução de view para o relacionamento many-to-many entre Usuário e Perfil, lá em baixo (veja Atribuir Perfis).
Ele usa dois listboxes do tipo multiple, e assim seleciona quais perfis o usuário tem.
Olhar o código fonte do AppFuse é uma boa inspiração, para Java (mas facilmente adaptável para Groovy).
Abcs
Postar um comentário