插入操作失败,sqlalchemy中的null Identity键错误+ sqlite

发布于 2025-01-29 03:01:54 字数 3476 浏览 1 评论 0原文

tldr; 尝试将记录插入一个名为json_schema使用ORM Mapper类的表之后,我收到了错误:sqlalchemy.orm.orm.orm.orm.exc.flusherror:实例:实例< jsonschema,at 0x10657f730>具有NULL身份密钥。该错误的一部分读取“还确保在不适当的时间(例如在load()事件中)不会发生此flush()。 “在这种情况下,或者如何进一步帮助我解决问题。


在SQLite数据库中,我有一个名为JSON_SCHEMA的表,看起来像这样。该表中的主要键是由生成的4字节十六进制文本字符串(seals(hex(randyblob(4))))

CREATE TABLE json_schema (
        id TEXT DEFAULT (lower(hex(randomblob(4)))) NOT NULL, 
        body JSON NOT NULL, 
        date_added DATETIME NOT NULL, 
        title TEXT NOT NULL, 
        PRIMARY KEY (id)
);

我试图在以下代码中插入一行

# this function inserts one json schema into the json_schemas table for each
# file present in the json_schemas_folder
def load_json_schemas(session, json_schemas_folder):

    for obj in json_schemas_folder.glob('**/*'):

        if obj.is_file() and obj.suffix == '.json':
            
            title = obj.stem.split('_')[0]
            date_added_string = obj.stem.split('_')[1]
            date_added = datetime.strptime(date_added_string, '%Y-%m-%d') 
            body = obj.read_text()

            new_row = JsonSchema( # JsonSchema is an ORM-mapper class to the json_schema table
                title = title,
                body = body,
                date_added = date_added
            )
            
            # Added row to session here
            session.add(new_row)

engine = create_engine('sqlite:///my.db', echo = True)
Session = sessionmaker(bind=engine)
session = Session()

load_json_schemas(session, Path("../data/json_schemas"))
# session.flush() #<-uncommenting this does not resolve the error.
session.commit() 

问题:当我执行此脚本时,我遇到了以下错误(在此问题的TLDR部分中引用了该错误):

sqlalchemy.orm.exc.FlushError: 

Instance <JsonSchema at 0x10657f730> has a NULL identity key.  
If this is an auto-generated value, check that the database table allows generation 
of new primary key values, and that the mapped Column object is configured to expect 
these generated values.  Ensure also that this flush() is not occurring at an inappropriate 
time, such as within a load() event.

我检查了中提到的第一个问题此错误 - “检查数据库表是否允许生成新的主要键值” - 通过测试插入insert(其中ID不是指定的) 。这有效,因此不是错误的根源。

sqlite> insert into json_schema(body,date_added,title) values ('test','test','test');
sqlite> select * from json_schema;
cee94fc1|test|test|test

接下来,我检查了是否将映射的列对象配置为期望这些生成的值。” 在ORM类中。在下面的摘要中,您可以看到idJSonschema确实具有server_default设置,这使我相信这一点也是已经解决了。

@declarative_mixin
class DocumentMetadata:

    id = Column(Text, nullable=False, primary_key=True, server_default=text('(lower(hex(randomblob(4))))'))
    body = Column(JSON, nullable=False)
    date_added = Column(DATETIME, nullable=False)

    def __repr__(self):
        return f"<{self.__class__.__name__}{self.__dict__}>"

    @declared_attr
    def __tablename__(cls):
        return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()

class JsonSchema(Base, DocumentMetadata):
    title = Column(Text, nullable=False)

最后,错误读取“还请确保此flush()不会在不适当的时间(例如Load()事件中发生。 /code>在“适当的时间”发生?

tldr; After trying to insert a record into a table called json_schema using an ORM mapper class, I received the error: sqlalchemy.orm.exc.FlushError: Instance <JsonSchema at 0x10657f730> has a NULL identity key. Part of that error read "Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event.", and I'm not sure what an "inappropriate time" means in this context, or how it can further help me troubleshoot the issue.


In an sqlite database, I have a table called json_schema that looks like this. The primary key in this table is a 4-byte hexadecimal text string generated by (lower(hex(randomblob(4)))).

CREATE TABLE json_schema (
        id TEXT DEFAULT (lower(hex(randomblob(4)))) NOT NULL, 
        body JSON NOT NULL, 
        date_added DATETIME NOT NULL, 
        title TEXT NOT NULL, 
        PRIMARY KEY (id)
);

I attempted to insert a row in the following code block

# this function inserts one json schema into the json_schemas table for each
# file present in the json_schemas_folder
def load_json_schemas(session, json_schemas_folder):

    for obj in json_schemas_folder.glob('**/*'):

        if obj.is_file() and obj.suffix == '.json':
            
            title = obj.stem.split('_')[0]
            date_added_string = obj.stem.split('_')[1]
            date_added = datetime.strptime(date_added_string, '%Y-%m-%d') 
            body = obj.read_text()

            new_row = JsonSchema( # JsonSchema is an ORM-mapper class to the json_schema table
                title = title,
                body = body,
                date_added = date_added
            )
            
            # Added row to session here
            session.add(new_row)

engine = create_engine('sqlite:///my.db', echo = True)
Session = sessionmaker(bind=engine)
session = Session()

load_json_schemas(session, Path("../data/json_schemas"))
# session.flush() #<-uncommenting this does not resolve the error.
session.commit() 

The problem: when I execute this script, I'm met with the following error (which was referenced earlier in the tldr section of this question):

sqlalchemy.orm.exc.FlushError: 

Instance <JsonSchema at 0x10657f730> has a NULL identity key.  
If this is an auto-generated value, check that the database table allows generation 
of new primary key values, and that the mapped Column object is configured to expect 
these generated values.  Ensure also that this flush() is not occurring at an inappropriate 
time, such as within a load() event.

I checked on the first issue mentioned in this error – "check that the database table allows generation of new primary key values" – by testing an insert INSERT ( where the id was not specified) . This worked, so not the source of error.

sqlite> insert into json_schema(body,date_added,title) values ('test','test','test');
sqlite> select * from json_schema;
cee94fc1|test|test|test

Next, I checked whether "mapped Column object is configured to expect these generated values." in the ORM class. In the snippet below, you can see that the id column inhereted by JsonSchema does have the server_default set which leads me to believe this point is also already addressed.

@declarative_mixin
class DocumentMetadata:

    id = Column(Text, nullable=False, primary_key=True, server_default=text('(lower(hex(randomblob(4))))'))
    body = Column(JSON, nullable=False)
    date_added = Column(DATETIME, nullable=False)

    def __repr__(self):
        return f"<{self.__class__.__name__}{self.__dict__}>"

    @declared_attr
    def __tablename__(cls):
        return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()

class JsonSchema(Base, DocumentMetadata):
    title = Column(Text, nullable=False)

Lastly, the error reads "Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event." How can I determine if flush() is occurring at an "innapropriate time"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

御弟哥哥 2025-02-05 03:01:54

sqlalchemy尚未支持SQLITE返回SQLITE ,并且在这种情况下是ISN'ISN''的主要关键t由自动启动处理。在这种情况下,SQLalchemy必须执行默认生成的函数本身并明确插入生成的值。

为此,要么:

  1. 更改server_default = text('(seals(hex(randyblob(4)))))') to default = text = text(' RandomBlob(4)))))在列定义

    • 表定义将不再包含默认条款
  2. add default = default = text('(seals(hex(randyblob(4))))' )到列定义,将server_default留在

    • 该表将保留默认子句,尽管Sqlalchemy将始终覆盖它。

这在,特别是在情况4:不支持主键,返回或等效的部分部分。


第二种方法的新的ORM-Mapper类:

@declarative_mixin
class DocumentMetadata:

    # this is the id column for the second approach. 
    #notice that `default` and `server_default` are both set
    id = Column(
        Text, 
        nullable=False, 
        primary_key=True, 
        default=text('(lower(hex(randomblob(4))))'), 
        server_default=text('(lower(hex(randomblob(4))))')
    )
    
    body = Column(JSON, nullable=False)
    date_added = Column(DATETIME, nullable=False)

    def __repr__(self):
        return f"<{self.__class__.__name__}{self.__dict__}>"

    @declared_attr
    def __tablename__(cls):
        return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()

class JsonSchema(Base, DocumentMetadata):
    title = Column(Text, nullable=False)

SQLAlchemy does not yet support RETURNING for SQLite, and the primary key in this case isn't handled by AUTOINCREMENT. In such a case, SQLAlchemy must execute the default-generating function itself and explicitly insert the generated value.

To achieve this, either:

  1. change server_default=text('(lower(hex(randomblob(4))))') to default=text('(lower(hex(randomblob(4))))') in the column definition

    • the table definition will no longer contain the DEFAULT clause
  2. add default=text('(lower(hex(randomblob(4))))') to the column definition, leaving server_default in place

    • the table will retain the DEFAULT clause, although SQLAlchemy will always override it.

This is documented in Fetching Server-Generated Defaults, in particular in the Case 4: primary key, RETURNING or equivalent is not supported section.


The new ORM-mapper class for the second approach:

@declarative_mixin
class DocumentMetadata:

    # this is the id column for the second approach. 
    #notice that `default` and `server_default` are both set
    id = Column(
        Text, 
        nullable=False, 
        primary_key=True, 
        default=text('(lower(hex(randomblob(4))))'), 
        server_default=text('(lower(hex(randomblob(4))))')
    )
    
    body = Column(JSON, nullable=False)
    date_added = Column(DATETIME, nullable=False)

    def __repr__(self):
        return f"<{self.__class__.__name__}{self.__dict__}>"

    @declared_attr
    def __tablename__(cls):
        return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()

class JsonSchema(Base, DocumentMetadata):
    title = Column(Text, nullable=False)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文