SQLAlchemy ORM - Carga ansiosa

La carga ansiosa reduce el número de consultas. SQLAlchemy ofrece funciones de carga ansiosas invocadas a través de opciones de consulta que dan instrucciones adicionales a la consulta. Estas opciones determinan cómo cargar varios atributos mediante el método Query.options ().

Carga de subconsultas

Queremos que las facturas del cliente se carguen con entusiasmo. La opción orm.subqueryload () proporciona una segunda instrucción SELECT que carga completamente las colecciones asociadas con los resultados recién cargados. El nombre "subconsulta" hace que la instrucción SELECT se construya directamente a través de la consulta reutilizada e incrustada como una subconsulta en un SELECT contra la tabla relacionada.

from sqlalchemy.orm import subqueryload
c1 = session.query(Customer).options(subqueryload(Customer.invoices)).filter_by(name = 'Govind Pant').one()

Esto da como resultado las siguientes dos expresiones SQL:

SELECT customers.id 
AS customers_id, customers.name 
AS customers_name, customers.address 
AS customers_address, customers.email 
AS customers_email
FROM customers
WHERE customers.name = ?
('Govind Pant',)

SELECT invoices.id 
AS invoices_id, invoices.custid 
AS invoices_custid, invoices.invno 
AS invoices_invno, invoices.amount 
AS invoices_amount, anon_1.customers_id 
AS anon_1_customers_id
FROM (
   SELECT customers.id 
   AS customers_id
   FROM customers
   WHERE customers.name = ?) 
   
AS anon_1 
JOIN invoices 
ON anon_1.customers_id = invoices.custid 
ORDER BY anon_1.customers_id, invoices.id 2018-06-25 18:24:47,479 
INFO sqlalchemy.engine.base.Engine ('Govind Pant',)

Para acceder a los datos de dos tablas, podemos usar el siguiente programa:

print (c1.name, c1.address, c1.email)

for x in c1.invoices:
   print ("Invoice no : {}, Amount : {}".format(x.invno, x.amount))

El resultado del programa anterior es el siguiente:

Govind Pant Gulmandi Aurangabad [email protected]
Invoice no : 3, Amount : 10000
Invoice no : 4, Amount : 5000

Carga unida

La otra función se llama orm.joinedload (). Esto emite un LEFT OUTER JOIN. El objeto principal, así como el objeto o la colección relacionados, se cargan en un solo paso.

from sqlalchemy.orm import joinedload
c1 = session.query(Customer).options(joinedload(Customer.invoices)).filter_by(name='Govind Pant').one()

Esto emite la siguiente expresión dando la misma salida que la anterior:

SELECT customers.id 
AS customers_id, customers.name 
AS customers_name, customers.address 
AS customers_address, customers.email 
AS customers_email, invoices_1.id 
AS invoices_1_id, invoices_1.custid 
AS invoices_1_custid, invoices_1.invno 
AS invoices_1_invno, invoices_1.amount 
AS invoices_1_amount

FROM customers 
LEFT OUTER JOIN invoices 
AS invoices_1 
ON customers.id = invoices_1.custid

WHERE customers.name = ? ORDER BY invoices_1.id
('Govind Pant',)

OUTER JOIN resultó en dos filas, pero devuelve una instancia de Customer. Esto se debe a que Query aplica una estrategia de "uniquing", basada en la identidad del objeto, a las entidades devueltas. La carga ansiosa unida se puede aplicar sin afectar los resultados de la consulta.

El subqueryload () es más apropiado para cargar colecciones relacionadas mientras que joinload () es más adecuado para la relación de varios a uno.