by Anonymous » 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. />
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'))
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:
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.
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.
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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
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.
Code: Select all
session.expunge(client_info)
session.expire(client_info)
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:
Ich habe schon einige Antworten auf SO durchgemacht (z. B. dieses, aber keiner von ihnen scheint für mich zu funktionieren. />
[code]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'))
[/code]
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:
[code]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.
[/code]
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.[code]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]
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.[code]session.expunge(client_info)
session.expire(client_info)
[/code]
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: