【发布时间】:2015-04-20 18:07:36
【问题描述】:
根据我老板的建议,我们正在使用 Dapper 访问我们的数据库。由于这只是一个快速的一次性项目,他不想为这些对数据库的调用结果创建 POCO 对象,所以我们只是让 Dapper 返回 dynamic 对象。
所以我有几个 Web API 控制器,它们都来自同一个 BaseController。在基类中,我们有一个这样的方法:
protected dynamic ExecuteSingle(string sql, object parameters = null, bool useStoredProcedure = true) {
using (var db = ObjectFactory.GetInstance<IDbManager>())
{
var cmd = useStoredProcedure ? db.SetSpCommand(sql) : db.SetCommand(sql);
if (parameters != null)
{
cmd = cmd.SetParameters(parameters);
}
return cmd.ExecuteObject<dynamic>();
}
}
当获取该结果并将其作为参数传递给Ok() 返回值时,我们能够成功使用它。对象的所有属性都成功解析为 JSON 对象。
我现在正在处理另一段代码,我需要使用返回的数据来实现另一组功能,而不是立即将其吐出。
var sql = " SELECT Id FROM Table WHERE ReviewId = :ReviewId ";
dynamic dbSurvey = ExecuteSingle(sql, new {ReviewId = reviewId}, false);
var survey = sg.GetSurvey(new GetSurveyRequest(dbSurvey.Id));
然后在调用dbSurvey.Id 的最后一行失败,并出现异常提示
“object”不包含“Id”的定义
检查对象,那里有一个名为“Id”的属性。
我已经有checkedseveralquestions,即使它们都在处理匿名对象(我可以理解dynamic 在该标题下),我仍然在同一个程序集中,所以那些在这种情况下,关于匿名对象被声明为“内部”的观点不适用。
我还尝试将ExecuteSingle 的返回类型更改为ExpandoObject,但得到了相同的结果。
编辑 下面是如何调用它的屏幕截图,以及它包含的对象和属性。也许属性的格式可以帮助确定为什么找不到它。
我还使用 Watch 菜单尝试了各种访问属性的方法,但以下方法均无效:
dbSurvey["Id"]
(dbSurvey as IDictionary<string, long>)["Id"]
((IDictionary<string, int>)dbSurvey)["Id"]
这是运行时即时窗口中dbSurvey.GetType() 的结果:
{<>f__AnonymousType2`1[System.Int64]}
base: {Name = "<>f__AnonymousType2`1" FullName = "<>f__AnonymousType2`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
Assembly: {***.Web.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
AssemblyQualifiedName: "<>f__AnonymousType2`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], ***.Web.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
BaseType: {Name = "Object" FullName = "System.Object"}
ContainsGenericParameters: false
DeclaringMethod: 'dbSurvey.GetType().DeclaringMethod' threw an exception of type 'System.InvalidOperationException'
DeclaringType: null
FullName: "<>f__AnonymousType2`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
GenericParameterAttributes: 'dbSurvey.GetType().GenericParameterAttributes' threw an exception of type 'System.InvalidOperationException'
GenericParameterPosition: 'dbSurvey.GetType().GenericParameterPosition' threw an exception of type 'System.InvalidOperationException'
GUID: {382c0269-d631-3c89-a105-38a1be8a3db7}
IsConstructedGenericType: true
IsEnum: false
IsGenericParameter: false
IsGenericType: true
IsGenericTypeDefinition: false
IsSecurityCritical: true
IsSecuritySafeCritical: false
IsSecurityTransparent: false
MemberType: TypeInfo
MetadataToken: 33554480
Module: {***.Web.Test.dll}
Name: "<>f__AnonymousType2`1"
Namespace: null
ReflectedType: null
StructLayoutAttribute: {System.Runtime.InteropServices.StructLayoutAttribute}
TypeHandle: {System.RuntimeTypeHandle}
UnderlyingSystemType: {Name = "<>f__AnonymousType2`1" FullName = "<>f__AnonymousType2`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
【问题讨论】:
-
这种方法存在许多问题。从 1 开始,所有逻辑现在都将在您的控制器中进行,而不是在正确隔离的 DAL 中进行。 2,对象返回之前的任何转换也将发生在控制器中,更不用说现在确实无法管理,3,由于动态,每次调用都会对性能造成很小的影响。 4、没有一次性的项目。一些可怜的灵魂最终会支持它。那么,到底 POCO 又有什么害处呢??
-
项目经理非常了解所有这些。在我们编写代码的任何人能够在最初的设计会议上提出这些问题之前,他就驳斥了每一个问题。
-
dbSurvey.GetType().GetProperty("Id")是否返回某些内容或 null? -
@krillgar 使用
dbSurvey.GetType()。我认为动态对象很可疑......你告诉我们你正在使用 Dapper,但IDbManager、SetSpCommand和ExecuteObject不是“基础”Dapper(我现在正在查看 Dapper.dll) -
尽管您花费了尽可能多的时间来尝试破解它,但您可能已经创建并使用了所需的对象。此外,请尝试仅使用 dbSurvey 本身,而不是 dbSurvey.Id。或者,dbSurvey[0]。