Npgsql 禁用类型加载后复合值读取失败:MapComposite 还缺元数据
NoTypeLoading 不会只跳过无关类型而为 MapComposite 自动补齐目录元数据。Npgsql 10.0.3 的 schema 过滤仍查询系统目录;按实际权限目标选择普通列接口或单独设计元数据供给。
为了限制应用账号读取 PostgreSQL 系统目录,连接启用了 NoTypeLoading,随后即使已经调用 MapComposite<T>(),复合类型读取仍失败。这里要区分 CLR 映射与数据库类型元数据:注册类名和字段映射,并没有把服务端的 OID、字段顺序及字段类型一起交给驱动。
具体组合从 Npgsql 8.0.5、.NET 6 开始,换到 9.0.5 并限制类型加载 schema 后,仍需要访问 pg_class、pg_attribute 等目录。当前正式 10.0.3 也保留了类型发现与复合字段查询,不能把升级或 MapComposite 当作“只读取我登记的两个类型”的安全开关。
schema 过滤不改变账号的目录权限
SetTypeLoadingSchemas 可以减少要加载的类型范围,但类型发现仍会查询系统目录。10.0.3 的复合类型字段查询通过 pg_type、pg_namespace、pg_class 与 pg_attribute 关联,schema 条件过滤结果,没有把查询入口替换成另一套权限模型。
其配置还保留内置 schema 和部分类型的加载规则,因此也不是严格的已映射类型白名单。应用是否能够枚举其他对象,最终取决于数据库账号实际拥有的权限;仅让一次驱动查询返回更少行,不等于账号已经无法发出别的目录查询。
先用真实受限身份核对失败时需要的目录和类型,不要一遇到加载错误就把多张系统表的读取权限授给 PUBLIC。PUBLIC 涉及的身份范围与当前应用账号不同,可能改变原先刻意设置的可见性边界。
先决定复合值是否必须跨客户端边界
如果应用只需要某个视图或函数返回的业务字段,可以评估让数据库接口直接返回这些字段的普通列,客户端按已支持的基本类型读取,而不把自定义复合值作为一个字段传输。这样改变的是接口契约,需要同步调整 SQL、DTO、参数及空值处理;不能仅关闭类型加载后保留原来的复合映射调用。
在 10.0.3 中,类型加载可通过数据源 builder 配置禁用。以下是已有 NpgsqlDataSourceBuilder 上的片段,builder 沿用原连接与认证设置:
builder.ConfigureTypeLoading(options => options.EnableTypeLoading(false));
它会退回驱动内置的有限类型集合,不是“禁止广泛扫描,但自动为 MapComposite 补齐所需元数据”。采用前应列清实际使用的类型,确认基础查询、参数、数组或其他映射是否仍满足需求;不能只测一条整数查询。
确实必须保留复合类型,同时又不能开放原目录时,需要另行设计获准的元数据供给方式。自定义数据库信息加载器涉及实验接口,按内部查询或反射构造类型更依赖具体驱动实现;它不应被包装成几行稳定配置。需要承担类型依赖、字段变化、缓存刷新与升级维护,不能把这一工作隐藏在一份通用复制代码里。
用权限和数据两个结果验收
先保存原账号权限、类型定义与驱动配置,再用隔离身份验证:连接能建立,所需业务值与 NULL、嵌套或数组字段能按契约读取;不该暴露的目录信息也仍不能被该身份直接查询。接口改成普通列时,检查字段类型、顺序与名称,不只确认查询不再抛异常。
回退需要恢复配套的接口与类型加载策略,不能单独重新启用复合值传输,却仍禁止它所需的元数据。这里处理的是类型加载能力与权限目标不相容的边界,不通过扩大公共权限来消除一条驱动异常。


