Сбой сравнения даты и времени в LINQ Entity Framework 4.2 - PullRequest
1 голос
/ 09 февраля 2012

Followind описывает проблему, с которой я сталкиваюсь, используя EF 4.2 и LINQ.Я пробовал это на нескольких системах и на множестве разновидностей SQL (SQL Express и SQL 2008 R2 Sp1), VS 2010 Pro и Premium, как в 64-разрядных, так и в 32 двоичных файлах, как с отладчиком, так и пытался запустить двоичный файл напрямую,Мне интересно, против чего я наткнулся, если это проблема с EF или, скорее, проблема с моим кодом, и мне не хватает нюансов, связанных с LINQ или EF.Любая помощь будет принята с благодарностью, я буду в ней в течение 6 часов, мой Google JuJu недостаточно силен, я боюсь.

У меня есть простая модель с именем сеанс, состоящая из ID (Guid), Name (String)) и отметка времени (DateTime).Я могу добавить сеанс в dbcontext и в отладке проверил, что запись сеанса действительно хранится в базе данных.Отметка времени, используемая для создания объекта сеанса, хранится в локальной переменной, и сразу после сохранения я пытаюсь извлечь сеанс в новый экземпляр объекта сеанса.Код, который извлекает сеанс (LINQ), выдает «System.InvalidOperationException« Последовательность не содержит элементов »» со следующей трассировкой стека:

at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__0[TResult](IEnumerable`1 sequence)
at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.First[TSource](IQueryable`1 source)
at efwtf.Program.Main(String[] args) in d:\vs2010\efwtf\efwtf\Program.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Я могу углубиться в ctx.Sessions в отладчике и увидеть внабор результатов, который сеанс, который я пытаюсь получить, действительно существует, и если я переберу набор результатов и вручную сопоставлю две метки времени, я могу извлечь сеанс, как и ожидалось.Если я запускаю код и передаю значение метки времени для записи, которая была добавлена ​​в базу данных при предыдущем запуске, это работает.Я могу найти обходные пути, в худшем случае, возможно, изменив тип данных на строку, но меня беспокоит, что это не работает, я предполагаю, что может быть частью проблемы, что функциональность должна поддерживаться.Код следует.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    using System.ComponentModel.DataAnnotations;

    namespace efwtf
    {
       class Program
       {
          static void Main ( string[] args )
          {
             Context ctx = new Context ();
             DateTime ts = DateTime.UtcNow;
             Session s1 = new Session () { Id = Guid.NewGuid(), Name = "Testing", TimeStamp = ts };
             ctx.Sessions.Add ( s1 );
             ctx.SaveChanges ();

             Session s2 = ( from s in ctx.Sessions
                            where ( s.Name == "Testing" && s.TimeStamp.Equals ( ts ) )
                            select s ).First ();

             Console.WriteLine ( s2.Name, s2.TimeStamp );
          }
       }

       class Context : DbContext
       {
          public DbSet<Session> Sessions { get; set; }
       }

       class Session
       {
          [Key]
          public Guid Id { get; set; }
          public string Name { get; set; }
          public DateTime TimeStamp { get; set; }
       }
    }

Я пробовал варианты оператора LINQ, включая s.datetime.equals (ts) и datetime.compare (s.datetime, ts) == 0, но каждый раз, когда он выбрасываетто же исключение.

У кого-нибудь есть идеи?Это я?Этот код делает мой двоичный файл большим?= ^)

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 13 февраля 2012

Чтобы заставить это работать, я изменил столбец данных для TimeStamp, чтобы он стал типом данных DateTime2 в базе данных следующим образом.

class Session 
{ 
   [Key] 
   public Guid Id { get; set; } 
   public string Name { get; set; } 

   [Column(TypeName = "datetime2")]
   public DateTime TimeStamp { get; set; } 
} 

В конечном счете, считаю, что это обходной путь, учитывая, что проблема, по-видимому, в некотором роде связана с LINQ, однако она помогла мне преодолеть препятствие и решила, что я опубликую здесь, если кто-то еще столкнется с этим.

1 голос
/ 09 февраля 2012

Проверьте код ниже, это работает!Однако то, как это работает, не логично.Потому что, если вы посмотрите на значения note1 и note2, вы увидите, что значение даты сохраняется правильно, но не применяется в запросе как есть.

var date = new DateTime(ts.Year, ts.Month, ts.Day, ts.Hour, ts.Minute, ts.Second, ts.Millisecond);
Session s2 = (from s in ctx.Sessions
            where (s.Name == "Testing" && s.TimeStamp == date)
            select s).First();

var note1 = s2.TimeStamp == date;
var note2 = s2.TimeStamp == ts;

Я полагаю, что это какая-то ошибка, связанная с назначением Entity Frameworkзначение параметра @ p_ linq _0.Это запрос, который я проследил за выполнением, но я не смог найти значение, присвоенное @ p_ linq _0.

SELECT TOP (1) 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[TimeStamp] AS [TimeStamp]
FROM [dbo].[Sessions] AS [Extent1]
WHERE (N'Testing' = [Extent1].[Name]) AND ([Extent1].[TimeStamp] = @p__linq__0)
...