如果我在Oracle DB中有一个名为LastModified的TIMESTAMP(6) WITH TIMEZONE
列的表,我希望使用EntityFramework对其进行建模;是否可以将该列标记为DatabaseGeneratedOption.Computed?
我有上述表并已成功使用EF6和Oracle.ManagedDataAccess.Client创建模型first / db first edmx模型。根据文档,TIMESTAMP(6) WITH TIMEZONE
列被映射为DateTimeOffset,我手动将LastModified标记为Computed。
这适用于SELECT语句但是当我尝试进行更新时,我收到以下错误:
商店生成的“System.DateTime”类型的值不可能 转换为需要的类型为'System.DateTimeOffset'的值 成员'LastModified'的类型....
深入研究异常和堆栈跟踪产量:
从'System.DateTime'到'System.DateTimeOffset'的转换无效。
在System.Convert.DefaultToType(IConvertible值,Type targetType, IFormatProvider提供商) System.DateTime.System.IConvertible.ToType(Type type,IFormatProvider System.Convert.ChangeType(Object value,Type。) conversionType,IFormatProvider provider)at System.Data.Entity.Core.Mapping.Update.Internal.PropagatorResult.AlignReturnValue(对象 价值,Edm会员)
我花了一些时间查看EntityFramework源代码,似乎处理返回数据库生成的值的代码不使用与SELECT或Model Creation逻辑相同的映射逻辑。
这会导致TIMESTAMP(6) WITH TIMEZONE
在从数据库中作为数据库生成的值检索时映射到DateTime,然后在尝试将其转换为DateTimeOffset时失败。
这是已知/预期的行为吗?我错过了某个地方的设置吗?或者只有一个有限的类型子集可以在使用不是“无”的StoreGeneratedPatten时使用?
答案 0 :(得分:0)
调试了EntityFramework并最终完全绕过它后,我发现问题在于提供程序(Oracle.ManagedDataAccess.Client)。在具有TIMESTAMP(6) WITH TIMEZONE
计算列的表上通过EntityFramework进行UPDATE生成如下所示的sql:
DECLARE "COLUMNC_FOROUTPUT" TIMESTAMP WITH TIME ZONE;
BEGIN
UPDATE "SCHEMA"."TABLEA"
SET "COLUMNB" = :p0
WHERE ("COLUMNA" = :p1)
RETURNING "COLUMNC" INTO "COLUMNC_FOROUTPUT";
OPEN :p2 FOR
SELECT "COLUMNC_FOROUTPUT" AS "COLUMNC_FOROUTPUT" FROM dual;
END;
其中:p2
是REF CURSOR。如果将上述sql和适当的参数直接提供给ODP.Net,则使用ExecuteReader()
和reader.GetFieldValue<object>(0)
会产生类型为DateTime
的对象,这与TIMESTAMP(6) WITH TIMEZONE
相反应映射到(DateTimeOffset)。
我想还需要另外一个关于ODP.Net,REF CURSORS和TIMESTAMP WITH TIME ZONE映射的问题,因为我原来问题的答案似乎是“是的,但如果您使用的是最新版本的Oracle.ManagedDataAccess则不行。”客户作为提供者“。
实际上,如果涉及引用游标,则没有区别,问题在于Oracle.ManagedDataAccess.Client.OracleTypeMapper类,它将Timestamp与TZ映射到DateTime而不是DateTimeOffset。这将影响对OracleDataReader的任何GetFieldValue调用。
我已在ODP.Net论坛上询问question,看看是否有人可以确认这是否是正确行为。