5 votes

Les relations de clés étrangères manquent lors de la réflexion de la base de données dans SqlAlchemy

Je tente d'utiliser SqlAlchemy (0.5.8) pour interfacer de manière déclarative avec une base de données héritée en utilisant la réflexion. Mon code de test ressemble à ceci :

from sqlalchemy import *
from sqlalchemy.orm import create_session
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
engine = create_engine('oracle://schemaname:pwd@SID')
meta = MetaData(bind=engine)

class CONSTRUCT(Base):
    __table__ = Table('CONSTRUCT', meta, autoload=True)

class EXPRESSION(Base):
    __table__ = Table('EXPRESSION', meta, autoload=True)

session = create_session(bind=engine)

Maintenant, lorsque j'essaie d'exécuter une requête en utilisant la jointure entre ces deux tables (définie par une contrainte de clé étrangère dans le schéma oracle sous-jacent) :

print session.query(EXPRESSION).join(PURIFICATION)

... pas de chance :

sqlalchemy.exc.ArgumentError: Impossible de trouver des relations de clé étrangère entre 'EXPRESSION' et 'PURIFICATION'

Cependant :

>>> EXPRESSION.epiconstruct_pkey.property.columns 
[Column(u'epiconstruct_pkey', OracleNumeric(precision=10, scale=2, asdecimal=True,
length=None), ForeignKey(u'construct.pkey'), table=, nullable=False)]

>>> CONSTRUCT.pkey.property.columns
[Column(u'pkey', OracleNumeric(precision=38, scale=0, asdecimal=True, length=None),
table=, primary_key=True, nullable=False)]

Ce qui indique clairement que la réflexion a détecté la clé étrangère.

Où est-ce que je me trompe ?

6voto

Sherbil Points 11

Après avoir débogué le code + SqlAlchemy avec Eclipse, j'ai découvert que la liste des tables/colonnes est conservée en interne en minuscules. Ainsi, il n'y a jamais eu de possibilité de correspondance entre EXPRESSION.foreignkey et expression.foreignkey. D'où le message d'erreur.

En fouillant profondément dans la documentation SqlAlchemy (http://www.sqlalchemy.org/docs/reference/dialects/oracle.html#identifier-casing), j'ai ensuite trouvé ce qui suit:

"Dans Oracle, le dictionnaire de données représente tous les noms d'identifiants insensibles à la casse en utilisant du texte en MAJUSCULE. SqlAlchemy, d'autre part, considère qu'un nom d'identifiant entièrement en minuscules est insensible à la casse. Le dialecte Oracle convertit tous les identifiants insensibles à la casse vers ces deux formats lors de la communication au niveau du schéma, telle que la réflexion des tables et des index. L'utilisation d'un nom en MAJUSCULE du côté de SqlAlchemy indique un identifiant sensible à la casse, et SqlAlchemy va mettre le nom entre guillemets - cela pourrait provoquer des incohérences avec les données du dictionnaire de données reçues d'Oracle, donc à moins que les noms d'identifiants n'aient réellement été créés comme sensibles à la casse (c'est-à-dire en utilisant des noms entre guillemets), tous les noms en minuscules devraient être utilisés du côté de SqlAlchemy."

Ainsi, mon code fonctionne s'il ressemble à ceci (les différences sont uniquement des changements de cas):

from sqlalchemy import *
from sqlalchemy.orm import create_session
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
engine = create_engine('oracle://EPIGENETICS:sgc04lab@ELN')
meta = MetaData(bind=engine)

class construct(Base):
    __table__ = Table('construct', meta, autoload=True)

class expression(Base):
    __table__ = Table('expression', meta, autoload=True)

class purification(Base):
    __table__ = Table('purification', meta, autoload=True)

session = create_session(bind=engine)
print session.query(expression).join(purification,expression)

... qui renvoie:

SELECT expression.pkey AS expression_pkey, expression.cellline AS expression_cellline, expression.epiconstruct_pkey AS expression_epiconstruct_pkey, expression.elnexp AS expression_elnexp, expression.expression_id AS expression_expression_id, expression.expressioncomments AS expression_expressioncomments, expression.cellmass AS expression_cellmass, expression.datestamp AS expression_datestamp, expression.person AS expression_person, expression.soluble AS expression_soluble, expression.semet AS expression_semet, expression.scale AS expression_scale, expression.purtest AS expression_purtest, expression.nmrlabelled AS expression_nmrlabelled, expression.yield AS expression_yield
FROM expression JOIN purification ON expression.pkey = purification.epiexpression_pkey JOIN expression ON expression.pkey = purification.epiexpression_pkey

Affaire classée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X