[FIX] fields: avoid prefetching of one2many fields
authorMartin Trigaux <mat@openerp.com>
Mon, 1 Sep 2014 14:28:56 +0000 (16:28 +0200)
committerMartin Trigaux <mat@openerp.com>
Tue, 2 Sep 2014 11:34:57 +0000 (13:34 +0200)
When reading a one2many field, the inverse mapping of the lines (matching m2o -> lines of corresponding record) was instantiating each line and then triggering the prefect of fields.
To improve the performances, the inverse mapping is done in sql to avoid triggering the prefetching.

openerp/osv/fields.py

index 76aaadf..f27b737 100644 (file)
@@ -671,17 +671,27 @@ class one2many(_column):
             context = dict(context or {})
             context.update(self._context)
 
-        res = dict((id, []) for id in ids)
-
         comodel = obj.pool[self._obj].browse(cr, user, [], context)
         inverse = self._fields_id
         domain = self._domain(obj) if callable(self._domain) else self._domain
         domain = domain + [(inverse, 'in', ids)]
 
-        for record in comodel.search(domain, limit=self._limit):
-            # Note: record[inverse] can be a record or an integer!
-            assert int(record[inverse]) in res
-            res[int(record[inverse])].append(record.id)
+        records = comodel.search(domain, limit=self._limit)
+        record_ids = map(int, records)
+
+        res = dict((id, []) for id in ids)
+        if record_ids:
+            cr.execute('SELECT id, %(inverse)s \
+                       FROM %(rel)s \
+                       WHERE id in %%s ' % {
+                        'inverse': inverse,
+                        'rel': comodel._table,
+                    }, (tuple(record_ids),))
+            record_value_id = dict(cr.fetchall())
+            # match the result per id, preserving the order
+            for record in records:
+                key = record_value_id[record.id]
+                res[key].append(record.id)
 
         return res