1010"""Public API functions and helpers for declarative."""
1111from __future__ import annotations
1212
13+ import collections
1314from typing import Callable
1415from typing import TYPE_CHECKING
1516
16- from ... import inspection
1717from ...orm import exc as orm_exc
1818from ...orm import relationships
1919from ...orm .base import _mapper_or_none
2424from ...util import OrderedDict
2525
2626if TYPE_CHECKING :
27- from ...engine .reflection import Inspector
2827 from ...sql .schema import MetaData
2928
3029
@@ -385,12 +384,38 @@ def prepare(cls, engine):
385384
386385 to_map = _DeferredMapperConfig .classes_for_base (cls )
387386
388- with inspection .inspect (engine )._inspection_context () as insp :
387+ metadata_to_table = collections .defaultdict (set )
388+
389+ # first collect the primary __table__ for each class into a
390+ # collection of metadata/schemaname -> table names
391+ for thingy in to_map :
392+
393+ if thingy .local_table is not None :
394+ metadata_to_table [
395+ (thingy .local_table .metadata , thingy .local_table .schema )
396+ ].add (thingy .local_table .name )
397+
398+ # then reflect all those tables into their metadatas
399+ with engine .connect () as conn :
400+ for (metadata , schema ), table_names in metadata_to_table .items ():
401+ metadata .reflect (
402+ conn ,
403+ only = table_names ,
404+ schema = schema ,
405+ extend_existing = True ,
406+ autoload_replace = False ,
407+ )
408+
409+ metadata_to_table .clear ()
410+
411+ # .map() each class, then go through relationships and look
412+ # for secondary
389413 for thingy in to_map :
390- cls ._sa_decl_prepare (thingy .local_table , insp )
391414 thingy .map ()
415+
392416 mapper = thingy .cls .__mapper__
393417 metadata = mapper .class_ .metadata
418+
394419 for rel in mapper ._props .values ():
395420
396421 if (
@@ -401,41 +426,50 @@ def prepare(cls, engine):
401426 secondary_arg = rel ._init_args .secondary
402427
403428 if isinstance (secondary_arg .argument , Table ):
404- cls ._reflect_table (secondary_arg .argument , insp )
429+ secondary_table = secondary_arg .argument
430+ metadata_to_table [
431+ (
432+ secondary_table .metadata ,
433+ secondary_table .schema ,
434+ )
435+ ].add (secondary_table .name )
405436 elif isinstance (secondary_arg .argument , str ):
406-
407437 _ , resolve_arg = _resolver (rel .parent .class_ , rel )
408438
409439 resolver = resolve_arg (
410440 secondary_arg .argument , True
411441 )
442+ metadata_to_table [
443+ (metadata , thingy .local_table .schema )
444+ ].add (secondary_arg .argument )
445+
412446 resolver ._resolvers += (
413- cls ._sa_deferred_table_resolver (
414- insp , metadata
415- ),
447+ cls ._sa_deferred_table_resolver (metadata ),
416448 )
417449
418450 secondary_arg .argument = resolver ()
419451
452+ for (metadata , schema ), table_names in metadata_to_table .items ():
453+ metadata .reflect (
454+ conn ,
455+ only = table_names ,
456+ schema = schema ,
457+ extend_existing = True ,
458+ autoload_replace = False ,
459+ )
460+
420461 @classmethod
421462 def _sa_deferred_table_resolver (
422- cls , inspector : Inspector , metadata : MetaData
463+ cls , metadata : MetaData
423464 ) -> Callable [[str ], Table ]:
424465 def _resolve (key : str ) -> Table :
425- t1 = Table ( key , metadata )
426- cls . _reflect_table ( t1 , inspector )
427- return t1
466+ # reflection has already occurred so this Table would have
467+ # its contents already
468+ return Table ( key , metadata )
428469
429470 return _resolve
430471
431- @classmethod
432- def _sa_decl_prepare (cls , local_table , inspector ):
433- # autoload Table, which is already
434- # present in the metadata. This
435- # will fill in db-loaded columns
436- # into the existing Table object.
437- if local_table is not None :
438- cls ._reflect_table (local_table , inspector )
472+ _sa_decl_prepare = True
439473
440474 @classmethod
441475 def _sa_raise_deferred_config (cls ):
@@ -446,14 +480,3 @@ def _sa_raise_deferred_config(cls):
446480 "method is called on the class hierarchy."
447481 % orm_exc ._safe_cls_name (cls ),
448482 )
449-
450- @classmethod
451- def _reflect_table (cls , table , inspector ):
452- Table (
453- table .name ,
454- table .metadata ,
455- extend_existing = True ,
456- autoload_replace = False ,
457- autoload_with = inspector ,
458- schema = table .schema ,
459- )
0 commit comments