From 78524a04eb69ab0d82b15e2da350cb2e671bc8f8 Mon Sep 17 00:00:00 2001 From: Audit Bot Date: Mon, 29 Jun 2026 14:53:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=A4=8D=E5=AE=A12?= =?UTF-8?q?=E4=B8=AA=E5=BB=BA=E8=AE=AE=20(models=E6=B3=A8=E9=87=8A=20+=20N?= =?UTF-8?q?+1=E6=9F=A5=E8=AF=A2=20+=20=E4=BA=8B=E5=8A=A1=E8=BE=B9=E7=95=8C?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - models.py: 注释中旧模式名对齐 EditingMode 枚举 - list_by_user: 批量加载 segments 避免 N+1 查询 - create(): flush 替代 commit,create_segments 统一提交事务 --- packages/adapters/sqlalchemy_impl/models.py | 4 +-- .../sqlalchemy_impl/template_repository.py | 22 +++++++++++++-- packages/application/template/use_cases.py | 28 +++++++++---------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/packages/adapters/sqlalchemy_impl/models.py b/packages/adapters/sqlalchemy_impl/models.py index f5854e025..7bfc5fab2 100755 --- a/packages/adapters/sqlalchemy_impl/models.py +++ b/packages/adapters/sqlalchemy_impl/models.py @@ -287,7 +287,7 @@ class TemplateModel(Base): id = Column(String(36), primary_key=True) user_id = Column(String(36), nullable=False, index=True) name = Column(String(200), nullable=False) - mode = Column(String(30), nullable=False, index=True) # pip / person_narration / one_take / voice_over_mix + mode = Column(String(30), nullable=False, index=True) # EditingMode 枚举值: pip / voice_pip / one_take / voice_over category = Column(String(100), nullable=False, default="") tags = Column(JSON, nullable=False, default=list) title_config = Column(JSON, nullable=False, default=dict) @@ -307,7 +307,7 @@ class TemplateSegmentModel(Base): segment_order = Column(Integer, nullable=False) duration_min = Column(Float, nullable=False) duration_max = Column(Float, nullable=False) - material_type = Column(String(20), nullable=True) # 仅 voice_over_mix: 人物/场景 + material_type = Column(String(20), nullable=True) # 仅 voice_over 模式: 人物/场景 created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc)) diff --git a/packages/adapters/sqlalchemy_impl/template_repository.py b/packages/adapters/sqlalchemy_impl/template_repository.py index 38cabae5d..a006692ff 100644 --- a/packages/adapters/sqlalchemy_impl/template_repository.py +++ b/packages/adapters/sqlalchemy_impl/template_repository.py @@ -40,8 +40,23 @@ class SQLAlchemyTemplateRepository: .all() ) templates = [self._model_to_entity(m) for m in models] - for t in templates: - t.segments = self.list_segments(t.id) + # 批量加载所有 segments,避免 N+1 查询 + if templates: + template_ids = [t.id for t in templates] + seg_models = ( + self.session.query(TemplateSegmentModel) + .filter(TemplateSegmentModel.template_id.in_(template_ids)) + .order_by(TemplateSegmentModel.segment_order) + .all() + ) + # 按 template_id 分组 + seg_map: dict[str, list] = {} + for sm in seg_models: + seg_map.setdefault(sm.template_id, []).append( + self._segment_model_to_entity(sm), + ) + for t in templates: + t.segments = seg_map.get(t.id, []) return templates def get(self, template_id: str, user_id: str) -> Optional[Template]: @@ -74,7 +89,8 @@ class SQLAlchemyTemplateRepository: is_active=template.is_active, ) self.session.add(model) - self.session.commit() + # flush 而非 commit,让 create + create_segments 在同一事务中提交 + self.session.flush() self.session.refresh(model) result = self._model_to_entity(model) result.segments = template.segments diff --git a/packages/application/template/use_cases.py b/packages/application/template/use_cases.py index a6d112c32..f43cb0122 100644 --- a/packages/application/template/use_cases.py +++ b/packages/application/template/use_cases.py @@ -70,20 +70,20 @@ class CreateTemplateUseCase: ) template = self.repository.create(template) - if command.segments: - segments = [ - TemplateSegment( - id=uuid.uuid4().hex, - template_id=template.id, - segment_order=seg.segment_order, - duration_min=seg.duration_min, - duration_max=seg.duration_max, - material_type=seg.material_type, - ) - for seg in command.segments - ] - self.repository.create_segments(segments) - template.segments = segments + # 始终调用 create_segments 以确保在同一事务中提交 + segments = [ + TemplateSegment( + id=uuid.uuid4().hex, + template_id=template.id, + segment_order=seg.segment_order, + duration_min=seg.duration_min, + duration_max=seg.duration_max, + material_type=seg.material_type, + ) + for seg in command.segments + ] + self.repository.create_segments(segments) + template.segments = segments return template