Hi Michael,

On Fri, 2010-03-26 at 14:30 -0400, Michael Bayer wrote:

> here's the relevant bit of documentation:
> 
> http://www.sqlalchemy.org/docs/reference/orm/interfaces.html?highlight=mapperextension#sqlalchemy.orm.interfaces.MapperExtension.before_insert
> 
> Column-based attributes can be modified within this method which will
> result in the new value being inserted. However **no** changes to the
> overall flush plan can be made, and manipulation of the Session  will not
> have the desired effect. To manipulate the Session  within an extension,
> use SessionExtension.

Thanks for the pointer. I read that part before but was not sure if I
have to modify the flush plan.

I attached the modified source code that actually works.

I dislike this solution for the following reasons:

* The extension scans through all new instances which could be quite a
number.
* The session must be modified (okay, no real problem).
* In case multiple classes use the CommonStorage class, the
StorageExtension must be adjusted. It would be better to operate on
CommonStorage instances but I don't know how to find the related classes
before the whole thing goes to the database.


Another question: Any idea when the second SA book will be published? I
bought the Essential SA book but it is a bit outdated covering 0.4.x.

Thanks, Torsten

-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden

mailto:[email protected]
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

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

import sqlalchemy as sa
import sqlalchemy.orm as orm
import sqlalchemy.orm.interfaces as interfaces
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
import hashlib

Base = declarative_base()

class CommonStorage(Base):
    __tablename__ = "common"
    hashval = sa.Column(sa.String, primary_key=True)
    value = sa.Column(sa.LargeBinary)
    def __init__(self, v):
        self.value = v
        self.hashval = hashlib.md5(v).hexdigest()
    def joinFrom(self, session):
        copy = session.query(CommonStorage).filter(self.hashval==CommonStorage.hashval).first()
        return copy or self

class StorageUser(Base):
    __tablename__ = "user"
    id = sa.Column(sa.Integer, primary_key=True)
    ref = sa.Column(None, sa.ForeignKey(CommonStorage.hashval))
    rel = orm.relation(CommonStorage)
    value = association_proxy("rel", "value")

class StorageExtension(interfaces.SessionExtension):
    def before_flush(self, session, flush_context, instances=None):
        for d in session.new:
            if isinstance(d, StorageUser) and d.rel is not None:
                original = d.rel
                d.rel = d.rel.joinFrom(session)
                if original is not d.rel:
                    session.expunge(original)

engine = sa.create_engine("sqlite:///", echo=True)
Base.metadata.create_all(engine)
session = orm.sessionmaker(bind=engine, extension=StorageExtension(), autoflush=False)()

ua, ub = StorageUser(), StorageUser()
ua.value = ub.value = "Something"
session.add(ua)
session.commit()
session.add(ub)
session.commit()

Reply via email to