Проблема с форматированием даты в запросе Linq в C # ODP.NET - PullRequest
0 голосов
/ 20 декабря 2018

В настоящее время у меня в приложении есть модель, использующая ODP.NET от Oracle.Теперь я могу использовать linq-запросы.

Программа выполняет следующее:

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

s.UNLOADINGTIMEEND = DateTime?searchDate = DateTime

Код работает на моем компьютере, он возвращает мне список с правильными отправлениями.Все работает, за исключением другого компьютера, там он выдаст мне следующее внутреннее исключение:

Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-01843: Geen geldige maand.Bij OracleInternal.ServiceObjects.OracleConnectionImpl.VerifyExecution (Int32 & CursorID, булевы bThrowArrayBindRelatedErrors, SqlStatementType sqlStatementType, Int32 arrayBindCount, OracleException & exceptionForArrayBindDML, булевы & hasMoreRowsInDB, булева 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, булева & bBindParamPresent, Int64 & internalInitialLOBFS, OracleException & exceptionForArrayBindDML, OracleConnection соединение, oracleLogicalTransaction & oracleLogicalTransaction, IEnumerable`1 adrianParsedStmt, булева isDescribeOnly,Boolean isFromEF) bij Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader (булево требование, булево заполнениеRequest, поведение CommandBehavior)target, операция Func`3, TInterceptionContext interceptionContext, действие Action3 выполняется, действие Action 3 выполняется) bij System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader (команда DbCommand, DbCommandInterceptionContext interceptionContext) bij System.Data.Ent.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands (EntityCommand entityCommand, поведение CommandBehavior)

Обратите внимание: Geen geldig maand. означает Not a valid month. Оглядываясь назад на запрос Linq: s.UNLOADINGTIMEEND > searchDate * оба формат DateTime.Сравнивать их было бы легко.Я думаю, что это связано с NLS-dateformat.

NLS_DATE_FORMAT сервера DD-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 UNLOADINGTIMEEND имеет DATA_TYPE = DATE, который может быть обнуляемым.Я дважды проверил, и столбец таблицы (где я получаю информацию) также имеет тип DATE.

При замене p__linq__0 на TO_DATE('2018/12/13 11:00:00', 'YYYY/MM/DD HH:MI:SS') и выполнении запроса, сгенерированного Linq, я получилте же результаты, что и в моей программе.

Дополнительная информация:

  • .NET Framework 4.6.1 (из-за совместимости в нашей компании, которую я использую)
  • Oracle.ManagedDataAccess 18.3.0
  • Oracle.ManagedDataAccess.EntityFramework 18.3.0

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

Вы можете использовать CompareTo для DateTime, но это не совместимо с 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();
0 голосов
/ 11 января 2019

NLS_DATE_FORMAT был неправ.Каждый раз, когда вы открываете соединение, вы должны установить его правильно.Вы можете сделать это следующим образом:

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

Вот почему не было всегда неправильно на всех компьютерах.Для некоторых компьютеров NLS_DATE_FORMAT было уже правильно.

0 голосов
/ 20 декабря 2018

Свойство 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();

Вероятно, вы увидите ту же проблему.

Решение: никогда не используйте строки для представления DateTimes.DateTime не является строкой!

Как только кто-то или какая-то система где-то на этой планете, даже в Эйндховене, доставляет строку, которая должна представлять DateTime, немедленно преобразуйте ее в DateTime.

Преимущества состоят в том, что вы можете немедленно обнаруживать и решать любые проблемы с форматированием.DateTime будет независимым от культуры.

Сохраняйте DateTime как DateTime как можно дольше.Преобразуйте его в строку только тогда, когда вам нужно связаться с оператором или с внешней системой, которая не принимает DateTime.

Опять же, преимущество: только в момент представления вы точно знаете ожидаемый формат строки.Это работает, даже если система A хочет получить в формате yyyy-MM-dd, а система B хочет получить его в формате dd-MMM-yy: вы знаете, для какой системы вы форматируете, поэтому вы знаете ожидаемый формат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...