vladimir:

changeset 1510 contains a fairly dramatic change to the unit of work to account for the issue this test raises.   i should add some extra unit tests for it as well.  so its working now (although, tread carefully...)

the only change to your test I would suggest is to not redefine your "backref" property for 'specification' and instead do it inline:

specification_mapper = mapper(SpecLine, specification_table,
    properties=dict(
        master=relation(Assembly,
            foreignkey=specification_table.c.master_id,
            primaryjoin=specification_table.c.master_id==products_table.c.product_id,
            lazy=True, backref=backref('specification', primaryjoin=specification_table.c.master_id==products_table.c.product_id), uselist=False),
        slave=relation(Product,
            foreignkey=specification_table.c.slave_id,
            primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
            lazy=True, uselist=False),
        quantity=specification_table.c.quantity,
        )
    )

the issue was that the topological sorting, which determines which kind of objects to save in what order as well as matching new primary key ids to foreign objects, was wrong.   It now considers inheritance hierarchies to all be under one "task" instead of breaking them up.  to distill your program down to the actual issue is this:

from sqlalchemy import *

metadata = BoundMetaData('sqlite://', echo=True)

products_table = Table('products', metadata,
   Column('product_id', Integer, primary_key=True),
   Column('product_type', String(128)),
   Column('name', String(128)),
   )

specification_table = Table('specification', metadata,
    Column('spec_line_id', Integer, primary_key=True),
    Column('slave_id', Integer, ForeignKey("products.product_id"),
        nullable=True),
    )

class Product(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.name)

class Detail(Product):
    pass

class SpecLine(object):
    def __init__(self, slave=None):
        self.slave = slave
    def __repr__(self):
        return '<%s %s>' % (
            self.__class__.__name__,
            getattr(self.slave, 'name', None)
            )

product_mapper = mapper(Product, products_table,
    polymorphic_on=products_table.c.product_type,
    polymorphic_identity='product')

detail_mapper = mapper(Detail, inherits=product_mapper,
    polymorphic_identity='detail')

specification_mapper = mapper(SpecLine, specification_table,
    properties=dict(
        slave=relation(Product,
            foreignkey=specification_table.c.slave_id,
            primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
            lazy=True, uselist=False),
        )
    )

metadata.create_all()
session = create_session(echo_uow=True)

s = SpecLine(slave=Product(name='p1'))
s2 = SpecLine(slave=Detail(name='d1'))
session.save(s)
session.save(s2)
session.flush()
session.clear()
print session.query(SpecLine).select()



On May 25, 2006, at 7:24 AM, Vladimir Iliev wrote:

from sqlalchemy import *

from datetime import datetime



metadata = BoundMetaData('sqlite://', echo=False)



products_table = Table('products', metadata,

   Column('product_id', Integer, primary_key=True),

   Column('product_type', String(128)),

   Column('name', String(128)),

   Column('mark', String(128)),

   Column('material', String(128), default=''),

   Column('sortament', String(128), default=''),

   Column('weight', String(128), default=''),

   )



specification_table = Table('specification', metadata,

    Column('spec_line_id', Integer, primary_key=True),

    Column('master_id', Integer, ForeignKey("products.product_id"),

        nullable=True),

    Column('slave_id', Integer, ForeignKey("products.product_id"),

        nullable=True),

    Column('quantity', Float, default=1.),

    )



class Product(object):


    def __init__(self, name, mark=''):

        self.name = name

        self.mark = mark


    def __repr__(self):

        return '<%s %s>' % (self.__class__.__name__, self.name)



class Detail(Product):


    def __init__(self, name, mark='', material='', sortament='', weight=''):

        self.name = name

        self.mark = mark

        self.material = material

        self.sortament = sortament

        self.weight = weight



class Assembly(Product): pass



class SpecLine(object):

    

    def __init__(self, master=None, slave=None, quantity=1):

        self.master = master

        self.slave = slave

        self.quantity = quantity

    

    def __repr__(self):

        return '<%s %.01f %s>' % (

            self.__class__.__name__,

            self.quantity or 0.,

            getattr(self.slave, 'name', None)

            )




product_mapper = mapper(Product, products_table,

    polymorphic_on=products_table.c.product_type,

    polymorphic_identity='product')


detail_mapper = mapper(Detail, inherits=product_mapper,

    polymorphic_identity='detail')


assembly_mapper = mapper(Assembly, inherits=product_mapper,

    polymorphic_identity='assembly')


specification_mapper = mapper(SpecLine, specification_table,

    properties=dict(

        master=relation(Assembly,

            foreignkey=specification_table.c.master_id,

            primaryjoin=specification_table.c.master_id==products_table.c.product_id,

            lazy=True, backref='specification', uselist=False),

        slave=relation(Product, 

            foreignkey=specification_table.c.slave_id,

            primaryjoin=specification_table.c.slave_id==products_table.c.product_id,

            lazy=True, uselist=False),

        quantity=specification_table.c.quantity,

        )

    )


assembly_mapper.add_property('specification',

    relation(SpecLine,

        primaryjoin=specification_table.c.master_id==products_table.c.product_id,

        lazy=True, private=True, backref='master')

    )





metadata.create_all()

session = create_session()



a1 = Assembly(name='a1')


p1 = Product(name='p1')

a1.specification.append(SpecLine(slave=p1))


d1 = Detail(name='d1')

a1.specification.append(SpecLine(slave=d1))


session.save(a1)


session.flush()

session.clear()


a1 = session.query(Product).get_by(name='a1')

print a1

print a1.specification


Reply via email to