Wie repariere ich `InvalyRequesterror: Kann Instanz ` in Sqlalchemy nicht anhängen?
Posted: 14 Apr 2025, 19:19
Ich habe schon einige Antworten auf SO durchgemacht (z. B. dieses, aber keiner von ihnen scheint für mich zu funktionieren. />
Mein Ziel war es, eine ordnungsgemäße bidirektionale Viele-zu-Viele-Beziehung aufzubauen, sodass ich auf das Objekt GroupInfo direkt aus einem ClientInfo -Objekt zugreifen kann (das die Gruppen, in der der Benutzer befindet), und die Clientinfo Objekte aus GroupInfo AsyncIterator[AsyncSession]:
Session = sessionmaker(bind=self.__SQL_ENGINE, class_=AsyncSession)
if locked:
async with self.__LOCK:
async with Session() as session:
yield session
else:
async with Session() as session:
yield session
< /code>
Die Dinge schienen eine Weile zu funktionieren; Ich könnte die verschachtelten Objekte mit verschachtelten SelectInLoad [/code] Anweisungen abrufen:
error.
Beachten Sie, dass ich jedes Mal, wenn ich auf die Datenbank zugreifen möchte, eine neue Sitzung erstelle. Dies ist der wichtigste Teil der Transaktion, da ich in Zukunft auf die Client-Objekte in dieser Beziehung beziehe.
Dies geschieht höchstwahrscheinlich, da ich einige ClientInfo -Objekte lade, damit der Benutzer die Person auswählen kann. Dadurch wird sichergestellt, dass alle ClientInfo -Objekte, die ich an die Beziehung anhängen möchte, bereits in der Sitzung sind. Aber was mich überrascht, ist, dass dieser Wahlteil in einer separaten Sitzung in einer separaten Klasse durchgeführt wird.
Ich habe auch zwei Instanzvariablen in der Hauptklasse erstellt, die die clientInfo.group_objs field und gruppInfo.client_objs Beziehungen enthält und versuchen, zu verwenden, dass IF-Adding-addiert einen Fehler zurückgibt:
Code: Select all
import sqlalchemy as sqal
client_group_association = sqal.Table(
"client_group_association",
Base.metadata,
sqal.Column("client_id", sqal.UUID, sqal.ForeignKey("client_info.id"), primary_key=True),
sqal.Column("group_id", sqal.UUID, sqal.ForeignKey("group_info.id"), primary_key=True)
)
class ClientInfo(Base):
"""Stores information of clients."""
__tablename__ = "client_info"
id: Mapped[uuid6.UUID] = mapped_column(sqal.UUID(as_uuid=True), primary_key=True,
insert_default=uuid6.uuid7())
name: Mapped[str] = mapped_column(sqal.String, nullable=False)
email: Mapped[str] = mapped_column(sqal.String, nullable=False)
phone: Mapped[str] = mapped_column(sqal.String, nullable=False)
age: Mapped[int] = mapped_column(sqal.Integer, nullable=False)
# Other unrelated fields
groups: Mapped[List[uuid6.UUID]] = mapped_column(UUIDList, nullable=True)
group_objs: Mapped[List["GroupInfo"]] = relationship(
secondary=client_group_association,
back_populates="client_objs"
)
__table_args__ = (sqal.UniqueConstraint('name', 'email', 'phone', name='_unique_client_details'),
sqal.ForeignKeyConstraint(['groups'], ['group_info.id'],
onupdate='CASCADE', ondelete='CASCADE'))
class GroupInfo(Base):
"""Stores information of groups."""
__tablename__ = "group_info"
id: Mapped[uuid6.UUID] = mapped_column(sqal.UUID(as_uuid=True), primary_key=True,
insert_default=uuid6.uuid7())
location: Mapped[Locations] = mapped_column(sqal.Enum(Locations), nullable=False)
members: Mapped[List[uuid6.UUID]] = mapped_column(UUIDList, nullable=True)
client_objs: Mapped[List["ClientInfo"]] = relationship(
secondary=client_group_association,
back_populates="group_objs"
)
__table_args__ = (sqal.UniqueConstraint('members', name='_unique_members'),
sqal.ForeignKeyConstraint(['members'], ['client_info.id'],
onupdate='CASCADE', ondelete='CASCADE'))
Session = sessionmaker(bind=self.__SQL_ENGINE, class_=AsyncSession)
if locked:
async with self.__LOCK:
async with Session() as session:
yield session
else:
async with Session() as session:
yield session
< /code>
Die Dinge schienen eine Weile zu funktionieren; Ich könnte die verschachtelten Objekte mit verschachtelten SelectInLoad [/code] Anweisungen abrufen:
Code: Select all
stmt = select(ClientInfo).where(...)\
.limit(10)\
.options(selectinload(ClientInfo.group_objs)\
.selectinload(GroupInfo.client_objs)) # Force eager-loading
< /code>
Jedes Mal, wenn ich eine neue Gruppe erstellen möchte, bin ich jetzt mit < /p>
richtsqlalchemy.exc.InvalidRequestError: Can't attach instance ; another instance with key (, (UUID('019634d4-1422-7a0e-9a21-96941acc10dd'),), None) is already present in this session.
Beachten Sie, dass ich jedes Mal, wenn ich auf die Datenbank zugreifen möchte, eine neue Sitzung erstelle. Dies ist der wichtigste Teil der Transaktion, da ich in Zukunft auf die Client-Objekte in dieser Beziehung beziehe.
Code: Select all
group_info: GroupInfo = GroupInfo(id=uuid6.uuid7(),
location=self.location,
members=list(self.clients.keys()))
for client_info in self.clients.values():
group_info.client_objs.append(client_info)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
Code: Select all
session.expunge(client_info)
session.expire(client_info)