C# 中 Linq 查询中的日期格式问题 ODP.NET

Dateformat problem in Linq query in C# ODP.NET

目前我的应用程序中有一个模型使用来自 Oracle 的 ODP.NET。我现在可以使用 linq 查询了。

该程序确实执行了以下操作:

DateTime searchDate = DateTime.Now.AddDays(-days);
oracleShipments = oracleEntities.Shipments.Where(s => consignorCodes.Contains(s.CONSIGNOR) && s.UNLOADINGTIMEEND > searchDate).ToList();

s.UNLOADINGTIMEEND = 日期时间? searchDate = 日期时间

代码在我的电脑上有效,它returns给我一个包含正确发货的列表。除了另一台计算机外,一切正常,它会给我以下内部异常:

Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-01843: Geen geldige maand. bij OracleInternal.ServiceObjects.OracleConnectionImpl.VerifyExecution(Int32& cursorId, Boolean bThrowArrayBindRelatedErrors, SqlStatementType sqlStatementType, Int32 arrayBindCount, OracleException& exceptionForArrayBindDML, Boolean& hasMoreRowsInDB, Boolean bFirstIterationDone) bij OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteReader(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, OracleDataReaderImpl& rdrImpl, Int32 longFetchSize, Int64 clientInitialLOBFS, OracleDependencyImpl orclDependencyImpl, Int64[] scnForExecution, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Int64& internalInitialLOBFS, OracleException& exceptionForArrayBindDML, OracleConnection connection, OracleLogicalTransaction& oracleLogicalTransaction, IEnumerable`1 adrianParsedStmt, Boolean isDescribeOnly, Boolean isFromEF) bij Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior) bij Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteDbDataReader(CommandBehavior behavior) bij System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed) bij System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext) bij System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)

请注意:Geen geldig maand. 表示 Not a valid month. 回顾 Linq 查询:s.UNLOADINGTIMEEND > searchDate 一种 DateTime 格式。 比较它们是一件容易的事。我认为这与 NLS 日期格式有关。

服务器的NLS_DATE_FORMATDD-MON-RR

是否有可能使它在所有计算机上运行? 我更喜欢使用 Linq 而不是硬编码类型化查询。


linq 查询输出是

SELECT  "Extent1"."SHIPMENT" AS "SHIPMENT",  "Extent1"."CONSIGNOR" AS
"CONSIGNOR",  "Extent1"."UNLOADINGCOMPANY" AS "UNLOADINGCOMPANY", 
"Extent1"."UNLOADINGCITY" AS "UNLOADINGCITY", 
"Extent1"."UNLOADINGCOUNTRY" AS "UNLOADINGCOUNTRY", 
"Extent1"."UNLOADINGPLANNEDSTART" AS "UNLOADINGPLANNEDSTART", 
"Extent1"."UNLOADINGPLANNEDEND" AS "UNLOADINGPLANNEDEND", 
"Extent1"."UNLOADINGREALIZEDSTART" AS "UNLOADINGREALIZEDSTART", 
"Extent1"."UNLOADINGREALIZEDEND" AS "UNLOADINGREALIZEDEND", 
"Extent1"."UNLOADINGACTUALSTART" AS "UNLOADINGACTUALSTART", 
"Extent1"."UNLOADINGACTUALEND" AS "UNLOADINGACTUALEND", 
"Extent1"."UNLOADINGTIMESTART" AS "UNLOADINGTIMESTART", 
"Extent1"."UNLOADINGTIMEEND" AS "UNLOADINGTIMEEND",  "Extent1"."Fixed"
AS "Fixed" FROM (SELECT  "V_PERFORMANCETOOL"."SHIPMENT" AS
"SHIPMENT",  "V_PERFORMANCETOOL"."CONSIGNOR" AS "CONSIGNOR", 
"V_PERFORMANCETOOL"."UNLOADINGCOMPANY" AS "UNLOADINGCOMPANY", 
"V_PERFORMANCETOOL"."UNLOADINGCITY" AS "UNLOADINGCITY", 
"V_PERFORMANCETOOL"."UNLOADINGCOUNTRY" AS "UNLOADINGCOUNTRY", 
"V_PERFORMANCETOOL"."UNLOADINGPLANNEDSTART" AS
"UNLOADINGPLANNEDSTART", 
"V_PERFORMANCETOOL"."UNLOADINGPLANNEDEND" AS
"UNLOADINGPLANNEDEND", 
"V_PERFORMANCETOOL"."UNLOADINGREALIZEDSTART" AS
"UNLOADINGREALIZEDSTART", 
"V_PERFORMANCETOOL"."UNLOADINGREALIZEDEND" AS
"UNLOADINGREALIZEDEND", 
"V_PERFORMANCETOOL"."UNLOADINGACTUALSTART" AS
"UNLOADINGACTUALSTART",  "V_PERFORMANCETOOL"."UNLOADINGACTUALEND"
AS "UNLOADINGACTUALEND",  "V_PERFORMANCETOOL"."UNLOADINGTIMESTART"
AS "UNLOADINGTIMESTART",  "V_PERFORMANCETOOL"."UNLOADINGTIMEEND"
AS "UNLOADINGTIMEEND",  "V_PERFORMANCETOOL"."Fixed" AS "Fixed"
FROM "CUSTOMIZATION"."V_PERFORMANCETOOL" "V_PERFORMANCETOOL")
"Extent1" WHERE ((('Company1' = "Extent1"."CONSIGNOR") OR
('Company2' = "Extent1"."CONSIGNOR")) AND
("Extent1"."UNLOADINGTIMEEND" > :p__linq__0))


-- p__linq__0: '13-12-2018 10:27:16' (Type = Date, IsNullable = false)

-- Executing at 20-12-2018 10:27:17 +01:00

-- Completed in 471 ms with result: OracleDataReader

在 Oracle 视图中,UNLOADINGTIMEENDDATA_TYPE = DATE 可以为空。 我仔细检查了 table 的列(我在其中获取信息)也是类型 DATE.

当用 TO_DATE('2018/12/13 11:00:00', 'YYYY/MM/DD HH:MI:SS') 替换 p__linq__0 并执行 Linq 生成的查询时,我得到了与我的程序相同的结果。

附加信息:

属性 UnloadingTimeEnd 有一个 DateTime 值。我认为这个值是在你执行Get之后才计算出来的。这使得您在执行查询之前不会发现问题。

类似于以下内容:

class Shipment
{
     private string textUnloadingTimeEnd = ...;

     public DateTime UnloadingTime
     {
          get {return DateTime.Parse(textUnloadingTimeEnd); }
     }
}

要找到真正的原因:进行一个简单的查询,尝试获取卸载时间:

var unloadingTimes = oracleEntities.Shipments
    .Select(shipment => shipment.UnloadingTime)
    .ToList();

您可能会遇到同样的问题。

解决方案:永远不要使用字符串来表示日期时间。 DateTime 不是字符串!

只要这个星球上某个地方(甚至在埃因霍温)的某个人或某个系统提供了一个表示 DateTime 的字符串,立即将其转换为 DateTime。

优点是您可以立即检测并解决任何格式问题。 DateTime 将独立于文化。

尽可能将此 DateTime 保持为 DateTime。只有当您需要与操作员或不接受 DateTime 的外部系统通信时,才将其转换为字符串。

同样,优点:只有在表示的时候你才能准确地知道预期的字符串格式。即使系统 A 想要格式为 yyyy-MM-dd 而系统 B 想要格式为 dd-MMM-yy,这仍然有效:你知道你正在格式化哪个系统,所以你知道预期的格式。

您可以使用 DateTime 的 CompareTo,但这与 LinqToSql 不兼容,因此您必须在调用该方法之前调用 AsEnumerable()。

    DateTime searchDate = DateTime.Now.AddDays(-days);
    oracleShipments = oracleEntities.Shipments.Where(s => consignorCodes.Contains(s.CONSIGNOR))
                                              .AsEnumerable()
                                              .Where(s=> s.UNLOADINGTIMEEND.CompareTo(searchDate) > 0)
                                              .ToList();

NLS_DATE_FORMAT 是错误的。每次打开连接时,都必须正确设置。你可以这样做:

OracleEntities oracleEntities = new OracleEntities();
oracleEntities.Database.Connection.Open();
oracleEntities.Database.ExecuteSqlCommand("ALTER SESSION SET NLS_DATE_FORMAT='DD-MON-RR'");

这就是为什么 alwaysall 计算机上它不是错误的原因。对于某些计算机,NLS_DATE_FORMAT 已经正确。