2010/4/7 Lean <[email protected]>

> Hola gente,
>
> Después de un tiempo como "voyeur", voy a hacer mis primera consulta al
> grupo. Creo que es una tontería de principiante, y la verdad es que quería
> iniciarme en una consulta de mayor nivel  ;-(  pero bueno, aquí voy... Pido
> disculpas por lo largo del mail.
>

¡bienvenido!


> Tengo dos tablas, "clientes" y "hosts", mapeadas a través de ActiveRecord a
> clases Cliente y Host, según una relación "Cliente <1:n> Host".
>

asegurate de que las clases estén correctamente mapeadas... esto es, en
Cliente debería haber una sentencia "has_many :hosts" y en Host "belongs_to
:cliente" (para la memoria: belongs_to va del lado de la FK). Sugerencia:
acostumbrate a que todo tu código esté en un sólo idioma, no mezcles inglés
y español (como difícilmente logres tener TODO en español, esto significa
que deberías acostumbrarte a codear en inglés lamentablemente -- en
cualquier momento lanzamos "Rieles" :P).


> Utilizando un find convencional con joins y select, hago:
>
> @hosts = Host.find(:all, :joins => "as h inner join clientes as c on 
> c.id=h.cliente_id,
> :select => "h.*, c.nombre")
>
> Lo que obtengo es la lista de hosts que cumplen con el join, pero no me
> está incluyendo el "c.nombre", cosa que necesito.
>

El problema con esto es conceptual: estás utilizando Host para algo de
Cliente. Olvidate de que estás trabajando con SQL, trabajá con tus
entidades.

Si están bien mapeadas, sólo necesitás hacer esto:

@hosts = Host.all # esto es un shortcut, simil Host.find :all
nombre_primer_cliente = @hosts.first.cliente.nombre


> Por otro lado, una consulta como esta, sin el :select me da error:
>
> @hosts = Host.find(:all, :joins => "as h inner join clientes as c on c.id
> =h.cliente_id")
>
> ActiveRecord::StatementInvalid: Mysql::Error: Unknown table 'hosts': SELECT
> `hosts`.* FROM `hosts`  as h inner join clientes as c on h.cliente_id=c.id
>
>
> Entiendo que el error me lo dá la base de datos, puesto que no le gusta el
> SELECT "*`hosts`.**".
>
> Una expresión con un :joins de la siguiente manera, no me da error, pero
> tampoco me da las columnas de la otra tabla...
>
> @hosts = Host.find(:all, :joins => [:cliente])
>

Una sugerencia: dejá SQL (o "partes" de SQL), selects, joins, includes, etc,
para los casos complejos. Olvidate de que estás trabajando con una base de
datos SQL.

* :select no deberías usarlo jamás (sólo que realmente te encuentres que te
reporte un beneficio REAL de performance, son casos MUY aislados)
* :joins... tampoco (al menos hasta que salga Rails 3 que parece que sabe
mapearlo mejor)
* :include usalo como una optimización de performance nada más; tomando el
caso de los @hosts, imaginate un @hosts.each do |host| puts
host.cliente.nombre end, siendo @hosts como lo obtuve yo más arriba, eso
genera muchos queries SQL innecesarios, con :include podés evitar eso nada
más (googlealo hay buena info al respecto)


> Tal vez entendí mal, pero esto debería funcionar dandome no sólo los campos
> de host, sino tambien los de las tablas incluídas en :joins, no es así?
>

No. Con select podés forzarlo a que te aparezcan, por ejemplo, campos de
Cliente en Host. Esto está realmente mal, te lo dice alguien que heredó
código que hacía eso y se volvió loco. Usá ActiveRecord, para eso está.
@host.cliente es mucho más obvio lo que hace...


> Por último, la expresión @hosts[0].cliente.nombre o
> @hosts.first.cliente.nombre me da lo que busco, pero realiza consultas
> adicionales a la base que en este caso pequeño no sería problema, pero sí
> con tablas que manejan varios millones de registros tal como ocurre con
> otras de mis tablas.
>

primero encontrate con este problema, medí, y luego cambiá esto

@hosts = Host.all

por

@hosts = Host.all :include => :cliente

nada más (la consulta es igual)

Primero resolvé el problema, después optimizá.

¡¡Saludos y suerte!!

nachokb
_______________________________________________
Ruby mailing list
[email protected]
http://lista.rubyargentina.com.ar/listinfo.cgi/ruby-rubyargentina.com.ar

Responder a