如何通过列值在Dapper中创建对应类的实例?
单次查询根据列值实例化对应类的解决方案
问题场景
现有一张名为items的表,包含ID、Type、Name等字段。需要根据Type字段的值,将每行数据实例化为对应的类:Type为"Burger"时创建Burger类实例,为"Sandwich"时创建Sandwich类实例。
最初的实现是按类型分别发起查询,代码如下:
var sandwiches = conn.Query<Sandwich>("SELECT * FROM items WHERE Type = 'Sandwich'"); var burgers = conn.Query<Burger>("SELECT * FROM items WHERE Type = 'Burger'");
但这种方式的查询次数随类型数量增加,数据库往返开销较高,希望通过单次查询完成所有行的类实例化。
解决方案
方案1:单次查询后内存中分发类型
先一次性查询所有数据,再遍历结果根据Type字段映射到对应类,仅需一次数据库请求:
// 查询所有数据(返回动态对象,也可使用匿名类或基类) var allItems = conn.Query("SELECT * FROM items"); // 初始化对应类的列表 var burgers = new List<Burger>(); var sandwiches = new List<Sandwich>(); foreach (var item in allItems) { switch (item.Type) { case "Burger": burgers.Add(new Burger { ID = item.ID, Name = item.Name // 按需映射其他属性 }); break; case "Sandwich": sandwiches.Add(new Sandwich { ID = item.ID, Name = item.Name // 按需映射其他属性 }); break; // 可添加其他类型的处理逻辑 } }
方案2:基于基类的类型转换(推荐)
如果Burger和Sandwich可以继承自同一个基类(比如FoodItem),可以先查询为基类实例,再转换为对应子类:
// 定义基类 public abstract class FoodItem { public int ID { get; set; } public string Type { get; set; } public string Name { get; set; } } // 子类实现 public class Burger : FoodItem { /* 子类特有属性 */ } public class Sandwich : FoodItem { /* 子类特有属性 */ } // 单次查询并转换为对应子类 var allFoodItems = conn.Query<FoodItem>("SELECT * FROM items") .Select(item => item.Type switch { "Burger" => new Burger { ID = item.ID, Type = item.Type, Name = item.Name }, "Sandwich" => new Sandwich { ID = item.ID, Type = item.Type, Name = item.Name }, _ => item // 或抛出异常处理未知类型 }) .ToList(); // 按需拆分列表 var burgers = allFoodItems.OfType<Burger>().ToList(); var sandwiches = allFoodItems.OfType<Sandwich>().ToList();
说明
两种方案都只需要一次数据库查询,减少了多次请求带来的网络开销和数据库连接消耗。如果表数据量极大,可结合分页查询优化内存占用,但常规场景下上述方式足够高效。
内容的提问来源于stack exchange,提问作者DusanInfinity
相关产品推荐
相关产品推荐

