ServiceStack.OrmLite:选择类型在运行时确定的POCO(继承)
ServiceStack.OrmLite: Selecting POCOs where Type is determined in runtime (inheritance)
当我在设计时不知道 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,但是当我读回它们时,我基本上只有一个Type,可能还有主键。 .Select<>
不起作用,因为我需要在运行时知道类型。
我发现了这个:
如果我理解正确,在设计时获取类型未知的 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 说过在持久化数据时使用继承是一个坏主意,他建议 "flatten" 层次结构。但是,我会伸出我的脖子并说在处理面向对象语言时,继承和多态性是不可避免的,而且 99.9% 的编码人员都无法避免 ;-))
OrmLite 中对使用运行时类型的支持非常有限。
在处理运行时类型时请参阅 OrmLite's Untyped API Support which gives you access to some Insert, Update and Delete APIs。
但是 SELECT 需要指定 select 的具体类型,即你可以 select 进入基础 class 与:
var results = db.Select<BaseClass>(typeOfObject);
但结果只会填充 BaseClass
属性。
一个可能的解决方案是使用 Dynamic Dictionary ResultSets API 到 select 结果到对象字典列表中,例如:
List<Dictionary<string,object>> results = db.Select<Dictionary<string,object>>(q);
然后使用FromObjectDictionary Reflection Utils将其转换为后期绑定类型,例如:
List<BaseClass> customers = results.Map(x => (BaseClass)x.FromObjectDictionary(customerType));
引用来源
(I have also noted that Mythz has said that using inheritance when persisting data is a bad idea and that he proposes to "flatten" the hierachy. However, I would stick my neck out and say that when dealing with Object Oriented languages, inheritance and polymorphism is unavoidable and not something 99.9% of the coders out there can do away with ;-))
如果你要引用某人的话,请逐字在你引用的来源中加上link,因为这是对我的错误陈述说过。
您可能引用了我强烈推荐 against using inheritance and base type properties and unknown late-bound types like interfaces and objects in DTOs 的回答。这是为了避免耦合到特定的序列化实现,并且是运行时序列化问题的主要来源,这与创建定义明确的可互操作服务的目标背道而驰。您可以避免此指南,但您的服务将仅适用于特定的序列化程序实现,在不同的语言中失败并且元数据支持有限,因为它们将无法静态推断您的服务合同中使用未知类型的漏洞。
但是这句话与 OrmLite 中的继承没有任何关系,您的 POCO 可以愉快地拥有任何级别的继承。问题是您正在尝试查询一个未知的后期绑定类型,因为 OrmLite 是一个代码优先的 ORM,带有类型 API 需要访问具体类型以支持其类型表达式 API 并填充其键入的结果。我上面的回答包括 OrmLite 对非类型化访问的有限支持。
当我在设计时不知道 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,但是当我读回它们时,我基本上只有一个Type,可能还有主键。 .Select<>
不起作用,因为我需要在运行时知道类型。
我发现了这个:
如果我理解正确,在设计时获取类型未知的 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 说过在持久化数据时使用继承是一个坏主意,他建议 "flatten" 层次结构。但是,我会伸出我的脖子并说在处理面向对象语言时,继承和多态性是不可避免的,而且 99.9% 的编码人员都无法避免 ;-))
OrmLite 中对使用运行时类型的支持非常有限。
在处理运行时类型时请参阅 OrmLite's Untyped API Support which gives you access to some Insert, Update and Delete APIs。
但是 SELECT 需要指定 select 的具体类型,即你可以 select 进入基础 class 与:
var results = db.Select<BaseClass>(typeOfObject);
但结果只会填充 BaseClass
属性。
一个可能的解决方案是使用 Dynamic Dictionary ResultSets API 到 select 结果到对象字典列表中,例如:
List<Dictionary<string,object>> results = db.Select<Dictionary<string,object>>(q);
然后使用FromObjectDictionary Reflection Utils将其转换为后期绑定类型,例如:
List<BaseClass> customers = results.Map(x => (BaseClass)x.FromObjectDictionary(customerType));
引用来源
(I have also noted that Mythz has said that using inheritance when persisting data is a bad idea and that he proposes to "flatten" the hierachy. However, I would stick my neck out and say that when dealing with Object Oriented languages, inheritance and polymorphism is unavoidable and not something 99.9% of the coders out there can do away with ;-))
如果你要引用某人的话,请逐字在你引用的来源中加上link,因为这是对我的错误陈述说过。
您可能引用了我强烈推荐 against using inheritance and base type properties and unknown late-bound types like interfaces and objects in DTOs 的回答。这是为了避免耦合到特定的序列化实现,并且是运行时序列化问题的主要来源,这与创建定义明确的可互操作服务的目标背道而驰。您可以避免此指南,但您的服务将仅适用于特定的序列化程序实现,在不同的语言中失败并且元数据支持有限,因为它们将无法静态推断您的服务合同中使用未知类型的漏洞。
但是这句话与 OrmLite 中的继承没有任何关系,您的 POCO 可以愉快地拥有任何级别的继承。问题是您正在尝试查询一个未知的后期绑定类型,因为 OrmLite 是一个代码优先的 ORM,带有类型 API 需要访问具体类型以支持其类型表达式 API 并填充其键入的结果。我上面的回答包括 OrmLite 对非类型化访问的有限支持。