首页 > 解决方案 > ServiceStack.OrmLite:选择在运行时确定类型的 POCO(继承)

问题描述

当我在设计时不知道 POCO 的确切类型时,如何使用 ServiceStack 中的 OrmLite 正确反序列化 POCO,但我只在运行时得到一个类型?

所以,像这样:

// Returns the object and can be cast to the correct subobject
public BaseClass ReadObject(Type typeOfObject, int id) 
{
     using (var db = _dbFactory.Open())
     {
         baseObject = db.Select<BaseClass>(typeOfObject, id);  // need something here...
         return baseObject;
     }
}

...
BaseClass bc = ReadObject(someType, 3); // someType = Customer for example

...
class BaseClass { ... }
class Actor : BaseClass { ... }
class Customer : Actor { ... }
class Operator : Actor { ... }

我坚持 Actor 和 Customer,但是当我读回它们时,我基本上只有一个类型,可能还有主键。.Select<>不起作用,因为我需要在运行时知道类型。

我发现了这个: 使用 servicestack ormlite 动态创建(并从中选择)表

如果我理解正确,在设计时获取类型未知的 POCO 的唯一方法是执行手动 SQL 语句,如答案中所示:

var modelDef = employeeType.GetModelMetadata();
var tableName = db.GetDialectProvider().GetQuotedTableName(modelDef);
var sql = $"SELECT * FROM {tableName}";

var results = db.Select<List<object>>(sql);
var results = db.Select<Dictionary<string,object>>(sql);
var results = db.Select<dynamic>(sql);

但是,这不会创建顶部列出的任何类;我需要将它类型转换为 BaseClass,但它当然应该是正确的对象(例如,'Customer'、'Operator' 等)。

我如何实现这一目标?

(我还注意到 Mythz 说过在持久化数据时使用继承是一个坏主意,并且他建议“扁平化”层次结构。但是,我会伸出脖子说在处理面向对象的语言时,继承和多态性是不可避免的,而且 99.9% 的程序员都无法摆脱它;-))

标签: inheritanceservicestackormlite-servicestack

解决方案


在 OrmLite 中使用运行时类型的支持非常有限。

请参阅OrmLite 的无类型 API 支持,它允许您在处理运行时类型时访问一些插入、更新和删除 API 。

但是 SELECT 需要指定要选择的具体类型,即您可以选择基类:

var results = db.Select<BaseClass>(typeOfObject);

但结果只会填充BaseClass属性。

一种可能的解决方案是使用动态字典结果集 API将结果选择到对象字典列表中,例如:

 List<Dictionary<string,object>> results = db.Select<Dictionary<string,object>>(q);

然后使用FromObjectDictionary Reflection Utils将其转换为后期绑定类型,例如:

List<BaseClass> customers = results.Map(x => (BaseClass)x.FromObjectDictionary(customerType));

引用来源

(我还注意到 Mythz 说过在持久化数据时使用继承是一个坏主意,并且他建议“扁平化”层次结构。但是,我会伸出脖子说在处理面向对象的语言时,继承和多态性是不可避免的,而且 99.9% 的程序员都无法摆脱它;-))

如果您要引用某人,请逐字逐句,包括指向您引用的来源的链接,因为这是对我所说的内容的歪曲。

您可能会参考我的回答,强烈建议不要使用继承和基本类型属性以及未知的后期绑定类型,例如 DTO 中的接口和对象。这是为了避免与特定的序列化实现耦合,并且是运行时序列化问题的主要来源,这与创建定义良好的可互操作服务的目标背道而驰。您可以避免使用此指南,但您的服务仅适用于特定的序列化程序实现,在不同的语言中失败并且元数据支持有限,因为它们无法静态推断您的服务合同中使用未知类型的漏洞。

但是这句话与 OrmLite 中的继承没有任何关系,您的 POCO 可以愉快地拥有任何级别的继承。问题是您正在尝试查询未知的后期绑定类型,其中 OrmLite 是具有类型化 API 的代码优先 ORM,需要访问具体类型以支持其类型化表达式 API 并填充其类型化结果。我上面的回答包括 OrmLite 对无类型访问的有限支持。


推荐阅读