运行时修改类属性:Petapoco跨PostgreSQL多Schema复用POCO咨询
动态Schema场景下Petapoco的POCO适配方案
首先明确:运行时直接修改[TableName]特性里的Schema部分不可行。因为.NET的特性是编译阶段就写入元数据的,运行时没办法直接修改特性的属性值。
下面给你几个实用的替代方案:
方案1:用自定义表名提供器动态拼接Schema
Petapoco自带了ITableNameProvider接口,能让你在运行时动态生成带Schema的完整表名,步骤如下:
- 实现这个接口,根据当前需要的Schema拼接表名:
public class DynamicSchemaTableNameProvider : ITableNameProvider { // 可以通过构造函数或者属性设置当前要用的Schema public string CurrentSchema { get; set; } = "public"; public string GetTableName(Type pocoType) { // 从POCO类上获取标记的基础表名 var tableAttr = pocoType.GetCustomAttribute<TableNameAttribute>(); if (tableAttr == null) throw new InvalidOperationException($"POCO类{pocoType.Name}没标记TableName特性"); // 提取纯表名(假设你把POCO的TableName特性只写表名,比如[TableName("table1")]) var baseTableName = tableAttr.Value.Split('.').Last(); // 拼接Schema和表名 return $"{CurrentSchema}.{baseTableName}"; } }
- 初始化Petapoco的
Database实例时,把这个自定义提供器传进去:
// 假设db是你的Database实例 db.TableNameProvider = new DynamicSchemaTableNameProvider { CurrentSchema = "schema1" }; // 之后用强类型查询时,会自动用schema1.table1 var dataList = db.Fetch<SomePoco>(); // 手动写SQL的话也可以直接调用获取表名的方法 var singleItem = db.Single<SomePoco>($"SELECT * FROM @0 WHERE id = @1", db.TableNameProvider.GetTableName(typeof(SomePoco)), 1);
方案2:手动指定带Schema的表名执行CRUD
如果场景简单,直接在每次操作时手动传入完整表名就行,不用依赖特性:
- 查询示例:
string targetSchema = "schema1"; var items = db.Fetch<SomePoco>($"SELECT * FROM {targetSchema}.table1");
- 插入示例:
var newItem = new SomePoco { Id = 2 }; db.Insert($"{targetSchema}.table1", "id", newItem);
这种方式直接,但如果操作多的话代码会有点重复,适合Schema切换不频繁的场景。
方案3:封装扩展方法简化操作
可以给Petapoco的Database类写扩展方法,把Schema切换的逻辑封装起来,减少重复代码:
- 先给POCO统一加个基类(可选,主要是约束类型):
public class BasePoco { } // POCO类只标记基础表名 [TableName("table1")] [PrimaryKey("id")] class SomePoco : BasePoco { [Column("id")]public int Id { get; set; } // 其他属性 }
- 写扩展方法:
public static class DatabaseExtensions { public static List<T> FetchWithSchema<T>(this Database db, string schemaName) where T : BasePoco { var tableAttr = typeof(T).GetCustomAttribute<TableNameAttribute>(); var fullTableName = $"{schemaName}.{tableAttr.Value}"; return db.Fetch<T>($"SELECT * FROM {fullTableName}"); } // 同理封装Insert、Update等方法 public static void InsertWithSchema<T>(this Database db, string schemaName, T poco) where T : BasePoco { var tableAttr = typeof(T).GetCustomAttribute<TableNameAttribute>(); var primaryKeyAttr = typeof(T).GetCustomAttribute<PrimaryKeyAttribute>(); db.Insert($"{schemaName}.{tableAttr.Value}", primaryKeyAttr.Value, poco); } }
使用的时候就很简洁:
var targetSchema = "schema1"; var items = db.FetchWithSchema<SomePoco>(targetSchema);
内容的提问来源于stack exchange,提问作者Anchovy
相关产品推荐
相关产品推荐

