On Jan 11, 2011, at 8:51 AM, Erkan Özgür Yılmaz wrote:

> Hi all,
> 
> This is my first question regarding to SQLAlchemy, you can count me as a 
> newbie. Here is my problem:
> 
> I've this inheritance between my Python classes, everything were working fine 
> until last night when I've added another class to my inheritance hierarchy. 
> I've tried to find the cause of that pretty much read all the documentation 
> about session, but couldn't find any solution.
> 
> I'm going to try to reduce the things I'm writing here by not including all 
> the attributes/methods below, so warn me if you spot something:
> 
> This is the basic inheritance to let you figure out what is inheriting from 
> what:


There's a subtle configuration problem here that is causing the mapper to 
create the entity in the database in a way that throws it off when it goes to 
get it back.    Ticket #2019 is added for a warning to be emitted corresponding 
to this condition.   "linkTypes" has no primary key column, so that when the 
mapper inserts the rows for LinkType, it doesn't insert into the final 
"linkTypes" table.    Later, when you access .name, "sound_link_type" has been 
expired, which is the default behavior after a commit, and the mapper goes to 
load its data from all of its tables.    No row is present in linkTypes, so the 
load returns nothing and the mapper assumes the identity key has been deleted.

I'd also note that you probably don't need all those "inherit_condition" 
parameters, those are figured out automatically based on foreign keys - only if 
there are multiple ways to join between parent and child tables, and the mapper 
throws an error, do you need to use that param.

> 
> class SimpleEntity(object):
>     pass
> 
> class Entity(SimpleEntity):
>     pass
> 
> class TypeEntity(Entity):
>     pass
> 
> class LinkType(TypeEntity):
>     pass
> 
> 
> 
> Here are the Tables (just the ones used with these classes, there are a lot 
> other tables too, I can paste them here if you ask for):
> 
> # SIMPLE ENTITY
> simpleEntities = Table(
>     "simpleEntities", metadata,
>     Column("id", Integer, primary_key=True),
>     Column("name", String(256), nullable=False),
>     Column("description", String),
>     
>     Column(
>         "created_by_id",
>         Integer,
>         ForeignKey("users.id", use_alter=True, name="x")
>     ),
>     
>     Column(
>         "updated_by_id",
>         Integer,
>         ForeignKey("users.id", use_alter=True, name="x")
>     ),
>     
>     Column("date_created", DateTime),
>     Column("date_updated", DateTime),
>     Column("entity_type", String(128), nullable=False),
>     UniqueConstraint('name', 'entity_type')
> 
> )
> 
> 
> # ENTITY
> entities = Table(
>     "entities", metadata,
>     Column(
>         "id",
>         ForeignKey("simpleEntities.id"),
>         primary_key=True
>     ),
> )
> 
> 
> 
> # TYPEENTITIES
> typeEntities = Table(
>     "typeEntities", metadata,
>     Column(
>         "id",
>         Integer,
>         ForeignKey("entities.id"),
>         primary_key=True,
>     ),
> )
> 
> 
> # LINKTYPES
> linkTypes = Table(
>     "linkTypes", metadata,
>     Column(
>         "id",
>         Integer,
>         ForeignKey("typeEntities.id"),
>     ),
> )
> 
> 
> 
> Mappers:
> 
>     # SimpleEntity
>     mapper(
>         entity.SimpleEntity,
>         tables.simpleEntities,
>         properties={
>             "_name": tables.simpleEntities.c.name,
>             "name": synonym("_name"),
>             "_description": tables.simpleEntities.c.description,
>             "description": synonym("_description"),
>             "_created_by": relationship(
>                 user.User,
>                 backref="_entities_created",
>                 primaryjoin=tables.simpleEntities.c.created_by_id== \
>                             tables.users.c.id,
>                 post_update=True,
>                 uselist=False
>             ),
>             "created_by": synonym("_created_by"),
>             "_updated_by": relationship(
>                 user.User,
>                 backref="_entities_updated",
>                 primaryjoin=tables.simpleEntities.c.updated_by_id== \
>                             tables.users.c.id,
>                 post_update=True,
>                 uselist=False
>             ),
>             "updated_by": synonym("_updated_by"),
>             "_date_created": tables.simpleEntities.c.date_created,
>             "date_created": synonym("_date_created"),
>             "_date_updated": tables.simpleEntities.c.date_updated,
>             "date_updated": synonym("_date_updated")
>         },
>         polymorphic_on=tables.simpleEntities.c.entity_type,
>         polymorphic_identity="SimpleEntity"
>     )
> 
> 
>     # Entity
>     mapper(
>         entity.Entity,
>         tables.entities,
>         inherits=entity.SimpleEntity,
>         inherit_condition=tables.entities.c.id==tables.simpleEntities.c.id,
>         polymorphic_identity="Entity",
>         properties={
>             "_tags": relationship(
>                 tag.Tag,
>                 secondary=tables.entity_tags,
>                 backref="_entities"
>             ),
>             "tags": synonym("_tags")
>         }
>     )
> 
> 
>     # TypeEntity
>     mapper(
>         entity.TypeEntity,
>         tables.typeEntities,
>         inherits=entity.Entity,
>         inherit_condition=tables.typeEntities.c.id==tables.entities.c.id,
>         polymorphic_identity="TypeEntity",
>     )
> 
> 
> 
>     # LinkType
>     mapper(
>         types.LinkType,
>         tables.linkTypes,
>         inherits=entity.TypeEntity,
>         inherit_condition=tables.linkTypes.c.id==tables.typeEntities.c.id,
>         polymorphic_identity="LinkType",
>     )
> 
> 
> 
> Alright here it comes slowly, my session object is set up in another module 
> (like the classes, tables and mappers are all in seperate modules), but I'm 
> going to try to merge them here:
> 
> >>> engine = create_engine("sqlite:///:memory:", "echo":True)
> 
> here are calls for the mappers shown above:
> >>> mappers.setup()
> >>> create_all(engine)
> >>> Session = sessionmaker(bind=engine)
> >>> session = Session()
> 
> >>> sound_link_type = LinkType(name="Sound")
> >>> sound_linkt_type.__dict__
> {'_created_by': None, '_sa_instance_state': 
> <sqlalchemy.orm.state.InstanceState object at 0x19866d0>, '_description': '', 
> '_date_updated': datetime.datetime(2011, 1, 11, 15, 44, 27, 954088), 
> '_date_created': datetime.datetime(2011, 1, 11, 15, 44, 27, 954074), '_tags': 
> [], '_name': 'Sound', '_nice_name': 'sound', '_updated_by': None}
> 
> >>> session.add(sound_link_type)
> >>> session.commit()
> 2011-01-11 15:46:23,955 INFO sqlalchemy.engine.base.Engine.0x...8f50 BEGIN 
> (implicit)
> 2011-01-11 15:46:23,956 INFO sqlalchemy.engine.base.Engine.0x...8f50 INSERT 
> INTO "simpleEntities" (name, description, created_by_id, updated_by_id, 
> date_created, date_updated, entity_type) VALUES (?, ?, ?, ?, ?, ?, ?)
> 2011-01-11 15:46:23,957 INFO sqlalchemy.engine.base.Engine.0x...8f50 
> ('Sound', '', None, None, '2011-01-11 15:44:27.954074', '2011-01-11 
> 15:44:27.954088', 'LinkType')
> 2011-01-11 15:46:23,960 INFO sqlalchemy.engine.base.Engine.0x...8f50 INSERT 
> INTO entities (id) VALUES (?)
> 2011-01-11 15:46:23,961 INFO sqlalchemy.engine.base.Engine.0x...8f50 (3,)
> 2011-01-11 15:46:23,962 INFO sqlalchemy.engine.base.Engine.0x...8f50 INSERT 
> INTO "typeEntities" (id) VALUES (?)
> 2011-01-11 15:46:23,962 INFO sqlalchemy.engine.base.Engine.0x...8f50 (3,)
> 2011-01-11 15:46:23,964 INFO sqlalchemy.engine.base.Engine.0x...8f50 COMMIT
> 
> 
> >>> sound_link_type.__dict__
> {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 
> 0x19866d0>, '_nice_name': 'sound'}
> 
> 
> >>> sound_link_type.name
> 2011-01-11 15:47:00,570 INFO sqlalchemy.engine.base.Engine.0x...8f50 BEGIN 
> (implicit)
> 2011-01-11 15:47:00,571 INFO sqlalchemy.engine.base.Engine.0x...8f50 SELECT 
> "simpleEntities".description AS "simpleEntities_description", 
> "simpleEntities".date_updated AS "simpleEntities_date_updated", 
> "simpleEntities".date_created AS "simpleEntities_date_created", 
> "simpleEntities".name AS "simpleEntities_name", "simpleEntities".id AS 
> "simpleEntities_id", entities.id AS entities_id, "typeEntities".id AS 
> "typeEntities_id", "linkTypes".id AS "linkTypes_id", 
> "simpleEntities".created_by_id AS "simpleEntities_created_by_id", 
> "simpleEntities".updated_by_id AS "simpleEntities_updated_by_id", 
> "simpleEntities".entity_type AS "simpleEntities_entity_type" 
> FROM "simpleEntities" JOIN entities ON entities.id = "simpleEntities".id JOIN 
> "typeEntities" ON "typeEntities".id = entities.id JOIN "linkTypes" ON 
> "linkTypes".id = "typeEntities".id 
> WHERE "simpleEntities".id = ?
> 2011-01-11 15:47:00,571 INFO sqlalchemy.engine.base.Engine.0x...8f50 (3,)
> 2011-01-11 15:47:00,832 INFO sqlalchemy.engine.base.Engine.0x...8f50 SELECT 
> "simpleEntities".description AS "simpleEntities_description", 
> "simpleEntities".date_updated AS "simpleEntities_date_updated", 
> "simpleEntities".date_created AS "simpleEntities_date_created", 
> "simpleEntities".name AS "simpleEntities_name", "simpleEntities".id AS 
> "simpleEntities_id", entities.id AS entities_id, "typeEntities".id AS 
> "typeEntities_id", "linkTypes".id AS "linkTypes_id", 
> "simpleEntities".created_by_id AS "simpleEntities_created_by_id", 
> "simpleEntities".updated_by_id AS "simpleEntities_updated_by_id", 
> "simpleEntities".entity_type AS "simpleEntities_entity_type" 
> FROM "simpleEntities" JOIN entities ON entities.id = "simpleEntities".id JOIN 
> "typeEntities" ON "typeEntities".id = entities.id JOIN "linkTypes" ON 
> "linkTypes".id = "typeEntities".id 
> WHERE "simpleEntities".id = ?
> 2011-01-11 15:47:00,832 INFO sqlalchemy.engine.base.Engine.0x...8f50 (3,)
> sqlalchemy.orm.exc.ObjectDeletedError: Instance '<LinkType at 0x19865d0>' has 
> been deleted.
> 
> 
> any idea ??? (also for the sake of brevity I didn't include the echoed lines 
> when I call create_all, I can send it too if it will help)
> 
> E.Ozgur Yilmaz
> Lead Technical Director
> eoyilmaz.blogspot.com
> www.ozgurfx.com
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to