Thanks for taking the time to do this. The problem was, of course, on my side. What got me thinking it was a SQLAlchemy issue was that I thought I had read that SQLAlchemy assumes that the first integer column is an autoincrement. Sorry for the noise.
On Wed, Dec 16, 2020 at 5:00 PM Mike Bayer <mike...@zzzcomputing.com> wrote: > > I would ask if perhaps there are triggers in place or other server side > constructs that might be at play here. The issue would need to be > illustated via an MCVE otherwise. Below I've taken your model, extrapolated > from it the required Application and Enumeration classes, and am able to run > your bulk_save_objects() code without any errors on SQL Server Express > database, SQLAlchemy 1.3.20. I would try running this test script on a > **non-production** database (note that it drops the tables first so that it > is repeatable) to see if it succeeds without issue. > > > from sqlalchemy import Column > from sqlalchemy import create_engine > from sqlalchemy import ForeignKey > from sqlalchemy import Integer > from sqlalchemy import String > from sqlalchemy.ext.declarative import declarative_base > from sqlalchemy.orm import Session > > Base = declarative_base() > > > class Application(Base): > __tablename__ = "Application" > > appCode = Column(String(10), primary_key=True) > > > class Enumeration(Base): > __tablename__ = "Enumeration" > > enumID = Column(Integer, primary_key=True, autoincrement=False) > > > class Component(Base): > __tablename__ = "Component" > > appCode = Column( > ForeignKey("Application.appCode"), primary_key=True, nullable=False > ) > componentEnumID = Column( > ForeignKey("Enumeration.enumID"), > primary_key=True, > nullable=False, > autoincrement=False, > ) > > > e = create_engine( > > "mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+13+for+SQL+Server", > echo=True, > ) > Base.metadata.drop_all(e) > Base.metadata.create_all(e) > > session = Session(e) > session.add(Application(appCode="VCP00001")) > session.add(Enumeration(enumID=12)) > session.add(Enumeration(enumID=13)) > session.commit() > > > models = [] > model = Component() > model.appCode = "VCP00001" > model.componentEnumID = 12 > models.append(model) > model = Component() > model.appCode = "VCP00001" > model.componentEnumID = 13 > models.append(model) > session.bulk_save_objects(models) > session.commit() > > > the INSERT statements look like: > > 2020-12-16 16:55:22,983 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) > 2020-12-16 16:55:22,986 INFO sqlalchemy.engine.base.Engine INSERT INTO > [Enumeration] ([enumID]) VALUES (?) > 2020-12-16 16:55:22,986 INFO sqlalchemy.engine.base.Engine ((12,), (13,)) > 2020-12-16 16:55:23,014 INFO sqlalchemy.engine.base.Engine INSERT INTO > [Application] ([appCode]) VALUES (?) > 2020-12-16 16:55:23,014 INFO sqlalchemy.engine.base.Engine ('VCP00001',) > 2020-12-16 16:55:23,064 INFO sqlalchemy.engine.base.Engine COMMIT > 2020-12-16 16:55:23,075 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) > 2020-12-16 16:55:23,077 INFO sqlalchemy.engine.base.Engine INSERT INTO > [Component] ([appCode], [componentEnumID]) VALUES (?, ?) > 2020-12-16 16:55:23,077 INFO sqlalchemy.engine.base.Engine (('VCP00001', 12), > ('VCP00001', 13)) > 2020-12-16 16:55:23,133 INFO sqlalchemy.engine.base.Engine COMMIT > > > > > > > On Wed, Dec 16, 2020, at 4:29 PM, Larry Martell wrote: > > I am providing both, e.g.: > > models = [] > model = Component() > model.appCode = 'VCP00001' > model.componentEnumID = 12 > models.append(model) > model = Component() > model.appCode = 'VCP00001' > model.componentEnumID = 13 > models.append(model) > session.bulk_save_objects(models) > > File "/opt/python/sqlalchemy/engine/base.py", line 1227, in _execute_context > self.dialect.do_executemany( > File "/opt/python/sqlalchemy/dialects/mssql/pyodbc.py", line 412, in > do_executemany > super(MSDialect_pyodbc, self).do_executemany( > File "/opt/python/sqlalchemy/engine/default.py", line 587, in do_executemany > cursor.executemany(statement, parameters) > pyodbc.IntegrityError: ('23000', "[23000] [Microsoft][ODBC Driver 17 > for SQL Server][SQL Server]Cannot insert the value NULL into column > 'componentEnumID', table 'DEC_CORE.dbo.Component'; column does not > allow nulls. INSERT fails. (515) (SQLExecDirectW)") > > The above exception was the direct cause of the following exception: > > Traceback (most recent call last): > File "/var/task/common/repository.py", line 52, in bulk_add > self._persist_records_and_clear_batch(batch) > File "/var/task/common/repository.py", line 82, in > _persist_records_and_clear_batch > self._session.bulk_save_objects(batch[:]) > File "/opt/python/sqlalchemy/orm/session.py", line 2733, in bulk_save_objects > self._bulk_save_mappings( > File "/opt/python/sqlalchemy/orm/session.py", line 2928, in > _bulk_save_mappings > transaction.rollback(_capture_exception=True) > File "/opt/python/sqlalchemy/util/langhelpers.py", line 68, in __exit__ > compat.raise_( > File "/opt/python/sqlalchemy/util/compat.py", line 178, in raise_ > raise exception > File "/opt/python/sqlalchemy/orm/session.py", line 2916, in > _bulk_save_mappings > persistence._bulk_insert( > File "/opt/python/sqlalchemy/orm/persistence.py", line 95, in _bulk_insert > _emit_insert_statements( > File "/opt/python/sqlalchemy/orm/persistence.py", line 1083, in > _emit_insert_statements > c = cached_connections[connection].execute(statement, multiparams) > File "/opt/python/sqlalchemy/engine/base.py", line 984, in execute > return meth(self, multiparams, params) > File "/opt/python/sqlalchemy/sql/elements.py", line 293, in > _execute_on_connection > return connection._execute_clauseelement(self, multiparams, params) > File "/opt/python/sqlalchemy/engine/base.py", line 1097, in > _execute_clauseelement > ret = self._execute_context( > File "/opt/python/sqlalchemy/engine/base.py", line 1287, in _execute_context > self._handle_dbapi_exception( > File "/opt/python/sqlalchemy/engine/base.py", line 1481, in > _handle_dbapi_exception > util.raise_( > File "/opt/python/sqlalchemy/util/compat.py", line 178, in raise_ > raise exception > File "/opt/python/sqlalchemy/engine/base.py", line 1227, in _execute_context > self.dialect.do_executemany( > File "/opt/python/sqlalchemy/dialects/mssql/pyodbc.py", line 412, in > do_executemany > super(MSDialect_pyodbc, self).do_executemany( > File "/opt/python/sqlalchemy/engine/default.py", line 587, in do_executemany > cursor.executemany(statement, parameters) > sqlalchemy.exc.IntegrityError: (pyodbc.IntegrityError) ('23000', > "[23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot > insert the value NULL into column 'componentEnumID', table > 'DEC_CORE.dbo.Component'; column does not allow nulls. INSERT fails. > (515) (SQLExecDirectW)") > [SQL: INSERT INTO [Component] ([appCode]) VALUES (?)] > [parameters: (('VCP00001',), ('VCP00001',))] > > On Wed, Dec 16, 2020 at 4:15 PM Mike Bayer <mike...@zzzcomputing.com> wrote: > > > > since these two columns have a ForeignKey on them, neither should default > > to using autoincrement behavior within the DDL phase. > > > > the error you are getting indicates that when you created a Component() > > object, one or both of these columns was not provided with an explicit > > value to be INSERTed. as for why it's "ignoring the values you > > provide" that can't be answered without a specific reproduction case. > > > > if the column does not have autoincrement, an explicit value must be > > provided to the object, *or* since these are foreign key columns, it > > implies you probably want to have the relationship() construct on other > > classes reponsible for populating these columns. it is also possible > > that if you do have relationship() constructs that refer to populating > > these columns, they might be stepping over your manually-provided values > > (although this is not what the error looks like), but again would need to > > see a complete example to know if something like that is happening here. > > > > > > > > On Wed, Dec 16, 2020, at 4:04 PM, Larry Martell wrote: > > > > Is there any way to have a Non auto increment integer primary key? I > > have this model: > > > > class Component(Base): > > __tablename__ = 'Component' > > > > appCode = Column(ForeignKey('Application.appCode'), > > primary_key=True, nullable=False) > > componentEnumID = Column(ForeignKey('Enumeration.enumID'), > > primary_key=True, nullable=False, autoincrement=False) > > > > And when I try and insert into it I get this warning: > > > > Column 'Component.componentEnumID' is marked as a member of the > > primary key for table 'Component', but has no Python-side or > > server-side default generator indicated, nor does it indicate > > 'autoincrement=True' or 'nullable=True', and no explicit value is > > passed. Primary key columns typically may not store NULL. Note that as > > of SQLAlchemy 1.1, 'autoincrement=True' must be indicated explicitly > > for composite (e.g. multicolumn) primary keys if > > AUTO_INCREMENT/SERIAL/IDENTITY behavior is expected for one of the > > columns in the primary key. > > > > And it ignores the values I provide for componentEnumID and generates > > SQL without that column, which then fails with: > > > > Cannot insert the value NULL into column 'componentEnumID', table > > 'DEC_CORE.dbo.Component'; column does not allow nulls. INSERT fails. > > > > How to get around this issue? > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/CACwCsY4s4C_SNDNHLWSDZxB%3DGTSL5q3UTuooAuxR68NshqRq%3DA%40mail.gmail.com. > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/dbe1586d-c6d9-45d9-a867-d7b747362387%40www.fastmail.com. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/CACwCsY4DfQs382e4OUAb78_8ZVcxZDhYMGXfs5dUzF7F_tvmgQ%40mail.gmail.com.