diff --git a/app/data/gpkg/dz_gis_center.gpkg b/app/data/gpkg/dz_gis_center.gpkg new file mode 100644 index 0000000..304c2c2 Binary files /dev/null and b/app/data/gpkg/dz_gis_center.gpkg differ diff --git a/app/data/gpkg/dz_gis_influence.gpkg b/app/data/gpkg/dz_gis_influence.gpkg new file mode 100644 index 0000000..dd27aa6 Binary files /dev/null and b/app/data/gpkg/dz_gis_influence.gpkg differ diff --git a/app/services/qgis/map_service.py b/app/services/qgis/map_service.py index 48a0cb1..c88cdc8 100644 --- a/app/services/qgis/map_service.py +++ b/app/services/qgis/map_service.py @@ -79,19 +79,43 @@ class MapService: return model["name"] def _fix_invalid_layers(self, project: QgsProject) -> None: - """只修复 TemplateModifier 处理后仍无效的图层""" + """修复 TemplateModifier 处理后仍无效的 PostgreSQL 图层。 + + 批量查询 DB 确认表存在性,只对存在的表执行 setDataSource 修复。 + """ t0 = time.time() db_config = self.config["db"] actual_schema = "qgis" - fixed = 0 - failed = 0 + invalid_pg = [] + valid_count = 0 total = 0 for layer in project.mapLayers().values(): if layer.providerType() != "postgres": continue total += 1 if layer.isValid(): + valid_count += 1 + continue + invalid_pg.append(layer) + + if not invalid_pg: + elapsed = time.time() - t0 + logger.info(f" 图层修正: 总计{total}个PG层, 全部有效, 耗时{elapsed:.3f}s") + return + + # 批量 DB 查询确认表存在性 + existing = self._batch_check_tables(db_config, actual_schema, invalid_pg) + + fixed = 0 + skipped_missing = 0 + failed = 0 + for layer in invalid_pg: + uri = layer.dataProvider().uri() + key = (uri.schema() or actual_schema, uri.table()) + if key not in existing: + logger.debug(f" 跳过不存在的表: {key[0]}.{key[1]} (图层: {layer.name()})") + skipped_missing += 1 continue try: self._fix_postgres_layer(layer, db_config, actual_schema) @@ -106,10 +130,53 @@ class MapService: elapsed = time.time() - t0 if total: logger.info( - f" 图层修正: 总计{total}个PG层, 跳过{total - fixed - failed}(已有效), " - f"修复{fixed}, 仍失败{failed}, 耗时{elapsed:.1f}s" + f" 图层修正: 总计{total}个PG层, 有效{valid_count}, " + f"跳过{skipped_missing}(表不存在), " + f"修复{fixed}, 仍失败{failed}, 耗时{elapsed:.3f}s" ) + @staticmethod + def _batch_check_tables(db_config, schema, layers): + """批量检查表是否存在(单次 DB 查询),返回存在的表集合""" + tables = set() + for layer in layers: + uri = layer.dataProvider().uri() + tables.add((uri.schema() or schema, uri.table())) + + if not tables: + return set() + + try: + import psycopg2 + conn = psycopg2.connect( + host=db_config["host"], + port=int(db_config["port"]), + dbname=db_config["database"], + user=db_config["username"], + password=db_config["password"], + connect_timeout=3, + ) + cur = conn.cursor() + conditions = " OR ".join( + "(table_schema = %s AND table_name = %s)" + for _ in tables + ) + params = [] + for s, t in tables: + params.extend([s, t]) + cur.execute( + f"SELECT table_schema, table_name FROM information_schema.tables " + f"WHERE {conditions}", + params, + ) + existing = {(row[0], row[1]) for row in cur.fetchall()} + cur.close() + conn.close() + return existing + except Exception as e: + logger.warning(f" 表存在性检查失败,将尝试修复所有图层: {e}") + return set(tables) + @staticmethod def _fix_postgres_layer(layer, db_config, actual_schema): """修正单个 PostgreSQL 图层的连接参数"""