是否可以在具有 EntityFramework 的 DateTimeOffset 列上使用 Computed 的 StoreGeneratedPattern?
Should it be possible to use a StoreGeneratedPattern of Computed on a DateTimeOffset column with EntityFramework?
如果我在 Oracle 数据库中有一个 table,其中有一个名为 LastModified 的 TIMESTAMP(6) WITH TIMEZONE
列,我希望使用 EntityFramework 对其建模;是否可以将该列标记为 DatabaseGeneratedOption.Computed?
我有前面提到的 table 并且已经成功地使用 EF6 和 Oracle.ManagedDataAccess.Client 创建了一个模型 first/db 第一个 edmx 模型。根据文档,TIMESTAMP(6) WITH TIMEZONE
列被映射为 DateTimeOffset,我手动将 LastModified 标记为 Computed。
这适用于 SELECT 语句,但是当我尝试进行更新时,出现以下错误:
A store-generated value of type 'System.DateTime' could not be
converted to a value of type 'System.DateTimeOffset' required for
member 'LastModified' of type ....
深入研究异常和堆栈跟踪产生:
Invalid cast from 'System.DateTime' to 'System.DateTimeOffset'.
at System.Convert.DefaultToType(IConvertible value, Type targetType,
IFormatProvider provider) at
System.DateTime.System.IConvertible.ToType(Type type, IFormatProvider
provider) at System.Convert.ChangeType(Object value, Type
conversionType, IFormatProvider provider) at
System.Data.Entity.Core.Mapping.Update.Internal.PropagatorResult.AlignReturnValue(Object
value, EdmMember member)
我花了一些时间查看 EntityFramework 源代码,似乎处理返回数据库生成值的代码没有使用与 SELECT 或模型相同的映射逻辑创作逻辑。
这导致 TIMESTAMP(6) WITH TIMEZONE
在作为数据库生成值从数据库检索时被映射到 DateTime,然后在尝试将其转换为 DateTimeOffset 时失败。
这是known/expected行为吗?我错过了某个地方的设置吗?或者在使用 StoreGeneratedPatten 时是否只有有限的类型子集可以使用 "None"?
调试 EntityFramework 并最终完全绕过它后,我发现问题出在提供程序 (Oracle.ManagedDataAccess.Client) 上。在具有 TIMESTAMP(6) WITH TIMEZONE
计算列的 table 上通过 EntityFramework 的更新生成如下所示的 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 映射的问题,因为我原来问题的答案似乎是 "Yes but not if you're using the latest version of Oracle.ManagedDataAccess.Client as a provider"。
更新
实际上,如果涉及引用游标,则没有任何区别,问题出在 Oracle.ManagedDataAccess.Client.OracleTypeMapper class 中,它将带 TZ 的时间戳映射到 DateTime 而不是 DateTimeOffset。这将影响对 OracleDataReader 上的 GetFieldValue 的任何调用。
我已经在 ODP.Net 论坛上询问了 question,看看是否有人可以确认这是否是正确的行为。
如果我在 Oracle 数据库中有一个 table,其中有一个名为 LastModified 的 TIMESTAMP(6) WITH TIMEZONE
列,我希望使用 EntityFramework 对其建模;是否可以将该列标记为 DatabaseGeneratedOption.Computed?
我有前面提到的 table 并且已经成功地使用 EF6 和 Oracle.ManagedDataAccess.Client 创建了一个模型 first/db 第一个 edmx 模型。根据文档,TIMESTAMP(6) WITH TIMEZONE
列被映射为 DateTimeOffset,我手动将 LastModified 标记为 Computed。
这适用于 SELECT 语句,但是当我尝试进行更新时,出现以下错误:
A store-generated value of type 'System.DateTime' could not be converted to a value of type 'System.DateTimeOffset' required for member 'LastModified' of type ....
深入研究异常和堆栈跟踪产生:
Invalid cast from 'System.DateTime' to 'System.DateTimeOffset'.
at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) at System.DateTime.System.IConvertible.ToType(Type type, IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at System.Data.Entity.Core.Mapping.Update.Internal.PropagatorResult.AlignReturnValue(Object value, EdmMember member)
我花了一些时间查看 EntityFramework 源代码,似乎处理返回数据库生成值的代码没有使用与 SELECT 或模型相同的映射逻辑创作逻辑。
这导致 TIMESTAMP(6) WITH TIMEZONE
在作为数据库生成值从数据库检索时被映射到 DateTime,然后在尝试将其转换为 DateTimeOffset 时失败。
这是known/expected行为吗?我错过了某个地方的设置吗?或者在使用 StoreGeneratedPatten 时是否只有有限的类型子集可以使用 "None"?
调试 EntityFramework 并最终完全绕过它后,我发现问题出在提供程序 (Oracle.ManagedDataAccess.Client) 上。在具有 TIMESTAMP(6) WITH TIMEZONE
计算列的 table 上通过 EntityFramework 的更新生成如下所示的 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 映射的问题,因为我原来问题的答案似乎是 "Yes but not if you're using the latest version of Oracle.ManagedDataAccess.Client as a provider"。
更新
实际上,如果涉及引用游标,则没有任何区别,问题出在 Oracle.ManagedDataAccess.Client.OracleTypeMapper class 中,它将带 TZ 的时间戳映射到 DateTime 而不是 DateTimeOffset。这将影响对 OracleDataReader 上的 GetFieldValue 的任何调用。
我已经在 ODP.Net 论坛上询问了 question,看看是否有人可以确认这是否是正确的行为。