Why does Session.merge only look at primary key and not all unique keys? Leaving aside some irritating DBMS restrictions on PKs and some automatic indexing that tends to happen, the PK is not fundamentally different than other unique keys and I don't see why SQLA distinguishes them from an integrity/relationship perspective. In databases where it is already frustrating that they have funky PK restrictions it is tough to make merge() work the way it seems it should. For example, in the code below this post, Sqlite requires the autoincrementing field to be the PK, and you can't composite it with another field... with these restrictions I can't get merge() to work the way "it should".
I was looking for a clean way in SQLAlchemy to do an "insert if not exists" pattern, and merge() looked perfect, but I can't make it work at the moment. I'm also aware that in the sample code the 'name' field should really just be the "primary" key and the problem goes away, but the reality of the grander/real scheme is that the linking id is needed in addition to other unique keys. In addition to the docs, these existing threads are also very relevant: http://groups.google.com/group/sqlalchemy/browse_frm/thread/7483736b46d56943 http://groups.google.com/group/sqlalchemy/browse_thread/thread/79736ff7ef81d1b9/0b80b54dc45ecc28 To make the "insert if not exists" pattern work I'll likely/ reluctantly be doing the __new__ hack referred to in the latter thread to achieve what I'm after in the end, but I really don't get why the PK is getting special treatment. Thanks, Russ Sample code: #### from sqlalchemy import Column, Integer, String, MetaData, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session import logging engine = create_engine('sqlite:///:memory:') metadata = MetaData() DeclarativeBase = declarative_base() #Configure some clean and indented SQL logging... class SqlFormatter(logging.Formatter): def format(self, record): prefix = " SQL >> " record.msg = prefix + record.msg.replace("\n", "\n" + prefix) return logging.Formatter.format(self, record) sqlaLogger = logging.getLogger('sqlalchemy.engine') sqlaLogger.setLevel(logging.INFO) handler = logging.StreamHandler() handler.setFormatter(SqlFormatter("%(message)s")) sqlaLogger.addHandler(handler) class MyStuff(DeclarativeBase): __tablename__ = 'mystuff' #Config below id = Column(Integer, primary_key = True, autoincrement = True) name = Column(String(100), nullable = False, unique = True) #Config below no good due to composite PK... #id = Column(Integer, primary_key = True, autoincrement = True) #name = Column(String(100), nullable = False, primary_key = True) #Config below doesn't give autoincrement... #id = Column(Integer, primary_key = False, autoincrement = True) #name = Column(String(100), nullable = False, primary_key = True) def __init__(self, Name): self.name = Name DeclarativeBase.metadata.create_all(engine) Session = sessionmaker(bind = engine) print "Attempting 'foo' merge into empty DB..." s1 = Session() foo = s1.merge(MyStuff("foo")) s1.commit() s1.close() print "Attempting 'foo' merge after it exists already..." s2 = Session() foo = s2.merge(MyStuff("foo")) s2.commit() s2.close() -- 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.