Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 防止SQLAlchemy自动设置IDENTITY\u INSERT_Python_Sql Server_Sqlalchemy - Fatal编程技术网

Python 防止SQLAlchemy自动设置IDENTITY\u INSERT

Python 防止SQLAlchemy自动设置IDENTITY\u INSERT,python,sql-server,sqlalchemy,Python,Sql Server,Sqlalchemy,我有一个带有自动递增主键的SQL Server表,我正在使用SQLAlchemy处理该表。如果我创建一个包含主键的表模型实例,而不是将其关闭,并调用session.add(instance),SQLAlchemy会自动向数据库发出SET IDENTITY\u INSERT[table]ON,插入成功 有没有办法自己控制这一切?如果我试图插入一个特定的主键而不是让它自动递增,我宁愿出错。如果我真的需要设置主键,我宁愿显式地告诉它 模型如下: Base = declarative_base() c

我有一个带有自动递增主键的SQL Server表,我正在使用SQLAlchemy处理该表。如果我创建一个包含主键的表模型实例,而不是将其关闭,并调用
session.add(instance)
,SQLAlchemy会自动向数据库发出
SET IDENTITY\u INSERT[table]ON
,插入成功

有没有办法自己控制这一切?如果我试图插入一个特定的主键而不是让它自动递增,我宁愿出错。如果我真的需要设置主键,我宁愿显式地告诉它

模型如下:

Base = declarative_base()

class Tub(Base):
    __tablename__ = 'Tub'

    id = Column('ID', Integer, primary_key=True, autoincrement=True)
    tare_weight = Column('TareWeight', Float(53), nullable=False)
下面是一个插入示例:

t = Tub(id=20, tare_weight=200)
session.add(t)
session.commit()
以下是生成的SQL:

BEGIN
SET IDENTITY_INSERT [Tub] ON
INSERT INTO [Tub] ([ID], [TareWeight]) VALUES (20, 200)
SET IDENTITY_INSERT [Tub] OFF
COMMIT
更新:

我意识到的另一个相关情况是:

t = Tub(id=20, tare_weight=200)
session.merge(t)
session.commit()
如果浴缸已经存在于数据库中,我希望更新其重量。如果没有,我希望插入失败,因为它包含一个显式主键。

根据:

对于不需要此默认生成的
IDENTITY
的情况,请为
列指定
False
。在第一个整数主键列上指定autoincrement
标志:

m=MetaData()
t=表('t',m,
列('id',整数,主键=True,自动递增=False),
列('x',整数))
m、 创建所有(引擎)
根据:

对于不需要此默认生成的
IDENTITY
的情况,请为
列指定
False
。在第一个整数主键列上指定autoincrement
标志:

m=MetaData()
t=表('t',m,
列('id',整数,主键=True,自动递增=False),
列('x',整数))
m、 创建所有(引擎)

为什么不重写构造函数呢

class-Tub(基本):
__tablename_uuu='Tub'
id=列('id',整数,主键=True,自动递增=True)
皮重重量=列('TareWeight',浮动(53),可为空=假)
定义初始化(self,id=None,**kwargs):
如果id不是无:
raisevalueerror(“嘿,不要传入'id`!”)
#或者你甚至可以忽略它被传入并发出警告。
超级()
如果希望将相同的方法应用于许多类,可以实现一个mixin:

导入警告
类自身免疫素:
id=列('id',整数,主键=True,自动递增=True)
定义初始化(self,id=None,**kwargs):
如果id不是无:
warnings.warn(“忽略了提供的`id`值”)
超级()
类别桶(基础,自增霉素):
皮重=。。。

为什么不重写构造函数呢

class-Tub(基本):
__tablename_uuu='Tub'
id=列('id',整数,主键=True,自动递增=True)
皮重重量=列('TareWeight',浮动(53),可为空=假)
定义初始化(self,id=None,**kwargs):
如果id不是无:
raisevalueerror(“嘿,不要传入'id`!”)
#或者你甚至可以忽略它被传入并发出警告。
超级()
如果希望将相同的方法应用于许多类,可以实现一个mixin:

导入警告
类自身免疫素:
id=列('id',整数,主键=True,自动递增=True)
定义初始化(self,id=None,**kwargs):
如果id不是无:
warnings.warn(“忽略了提供的`id`值”)
超级()
类别桶(基础,自增霉素):
皮重=。。。

长远来看,您可以进行完整的猴子修补。我不认为它解决了所有问题,但它确实阻止了使用
SET IDENTITY\u INSERT
。您可以使用monkey patch
MSExecutionContext
s和。例如:

from sqlalchemy import engine
from sqlalchemy.dialects.mssql.base import MSExecutionContext

def pre_exec(self):
    if self.isinsert:
        tbl = self.compiled.statement.table
        seq_column = tbl._autoincrement_column
        insert_has_sequence = seq_column is not None

        self._select_lastrowid = (
            not self.compiled.inline
            and insert_has_sequence
            and not self.compiled.returning
            and not self._enable_identity_insert
            and not self.executemany
        )


def post_exec(self):
    conn = self.root_connection
    if self._select_lastrowid:
        if self.dialect.use_scope_identity:
            conn._cursor_execute(
                self.cursor,
                "SELECT scope_identity() AS lastrowid",
                (),
                self,
            )
        else:
            conn._cursor_execute(
                self.cursor, "SELECT @@identity AS lastrowid", (), self
            )
        # fetchall() ensures the cursor is consumed without closing it
        row = self.cursor.fetchall()[0]
        self._lastrowid = int(row[0])

    if (
        self.isinsert or self.isupdate or self.isdelete
    ) and self.compiled.returning:
        self._result_proxy = engine.FullyBufferedResultProxy(self)


MSExecutionContext.pre_exec = pre_exec
MSExecutionContext.post_exec = post_exec
我粗略的例子是,这只正在使用的猴子修补了使用
\u enable\u identity\u insert
功能的函数,并删除了这些部分。现在,每次尝试插入ID时都会出现以下错误:

sqlalchemy.exc.IntegrityError:(pyodbc.IntegrityError)('23000',“[23000][Microsoft][SQL Server Native Client 11.0][SQL Server]在identity_insert设置为OFF时,无法在表'Tub'中为identity列插入显式值。(544)(SQLExecDirectW)”


您现在的问题可能是您完全依赖自动增量功能,但它可能对某些人有用,或者您可以找到其他方法来绕过此功能。

从长远来看,您可以完全使用猴子补丁。我不认为它解决了所有问题,但它确实阻止了使用
SET IDENTITY\u INSERT
。您可以使用monkey patch
MSExecutionContext
s和。例如:

from sqlalchemy import engine
from sqlalchemy.dialects.mssql.base import MSExecutionContext

def pre_exec(self):
    if self.isinsert:
        tbl = self.compiled.statement.table
        seq_column = tbl._autoincrement_column
        insert_has_sequence = seq_column is not None

        self._select_lastrowid = (
            not self.compiled.inline
            and insert_has_sequence
            and not self.compiled.returning
            and not self._enable_identity_insert
            and not self.executemany
        )


def post_exec(self):
    conn = self.root_connection
    if self._select_lastrowid:
        if self.dialect.use_scope_identity:
            conn._cursor_execute(
                self.cursor,
                "SELECT scope_identity() AS lastrowid",
                (),
                self,
            )
        else:
            conn._cursor_execute(
                self.cursor, "SELECT @@identity AS lastrowid", (), self
            )
        # fetchall() ensures the cursor is consumed without closing it
        row = self.cursor.fetchall()[0]
        self._lastrowid = int(row[0])

    if (
        self.isinsert or self.isupdate or self.isdelete
    ) and self.compiled.returning:
        self._result_proxy = engine.FullyBufferedResultProxy(self)


MSExecutionContext.pre_exec = pre_exec
MSExecutionContext.post_exec = post_exec
我粗略的例子是,这只正在使用的猴子修补了使用
\u enable\u identity\u insert
功能的函数,并删除了这些部分。现在,每次尝试插入ID时都会出现以下错误:

sqlalchemy.exc.IntegrityError:(pyodbc.IntegrityError)('23000',“[23000][Microsoft][SQL Server Native Client 11.0][SQL Server]在identity_insert设置为OFF时,无法在表'Tub'中为identity列插入显式值。(544)(SQLExecDirectW)”


您现在的问题可能是您完全依赖于自动增量功能,但它可能对某些人有用,或者您可以找到其他方法来绕过此功能。

我将添加我自己的答案,以详细说明我对@supershot答案的评论。我认为,如果要在一开始就阻止主键获取值,那么应该通过属性而不是构造函数来实现:

class Tub(Base):
    __tablename__ = 'Tub'

    __id = Column('ID', Integer, primary_key=True, autoincrement=True)
    tare_weight = Column('TareWeight', Float(53), nullable=False)

    @property
    def id(self):
        return self.__id
这会阻止您同时做这两件事,而不仅仅是第一件:

tub = Tub(id=5, tare_weight=100)

or

tub = Tub(tare_weight=100)
tub.id = 5
AttributeError:无法设置属性