Comparison of entities and DateTime accurate to milliseconds

I am having a problem with Entity Framework (Code First) in C # regarding comparing DateTime values. I use the Validity class below (simplified for this example) as a superclass of other entities that must have a certain certainty over time.

public abstract partial class Validity { [Key] public int ID { get; set; } public DateTime? ValidFrom { get; set; } public DateTime? ValidTo { get; set; } /** * @brief This method builds an IQueryable from another IQueryable, * with added restriction on ValidityFrom/To * * An object validitiy is defined to * 1. start at timestamp ValidFrom (=inclusive) and * 2. to end before ValidTo (=exclusive). * 3. If ValidFrom or ValidTo is NULL, it means to be "unbounded" * in start or end time (respectively) * **/ public static IQueryable<T> isValidAt<T>(IQueryable<T> query, DateTime time) where T : Validity { return query.Where<T>(c => (!c.ValidFrom.HasValue || time >= c.ValidFrom) // If ValidFrom != NULL, the given timestamp must be equal or "after" ValidFrom && (!c.ValidTo.HasValue || time < c.ValidTo)); // If ValidTo != NULL, the given timestamp must be "before" ValidTo } /** * @brief Shall invalidate the object at timestamp time (implicitly sets validTo attribute). **/ public void inValidate(DateTime time) { ValidTo = time; } } public class Item : Validity { public string property { get; set; } } 

On the last three lines you will find the "Item" class, which we will take as an example. Let's look at this query:

 DateTime requestTime = DateTime.Now; var items = from n in Validity.isValidAt(db.Items, requestTime) select n; 

This request should only return returned objects of the Item class that are "valid" in the "requestTime". Note that for ValidTo == requestTime, the element should be considered "invalid" (the time with a valid ValidFrom to ValidTo is -exclusive-ValidTo; see the comments in the source code above).

Problem

Actually the -have-result in my "items" result set has ValidTo == requestTime . I just checked it through

 Item i= items.FirstOrDefault(); if ((i.ValidFrom.HasValue && i.ValidFrom > requestTime) || (i.ValidTo.HasValue && requestTime >= i.ValidTo)) { // ... SOME ERROR OUTPUT ... } 

** NOTE: This error does not occur rarely, but almost all the time in software like .inValidate (requestTime); often calls an invalidate object. **

I manually checked using Microsoft SQL Server Management Studio (Microsoft SQL Server 2008 is used as a backend) using the received LinQ SQL query. I had to declare / install @ p__linq__0, @ p__linq__1 myself (which both mean requestTime) ...

 DECLARE @p__linq__0 DATETIME DECLARE @p__linq__1 DATETIME SET @p__linq__0 = '2012-10-23 15:15:11.473' SET @p__linq__1 = '2012-10-23 15:15:11.473' 

This works as expected. But if instead I use the value "2012-10-23 15:15:11", I will get the wrong results (as expected). They are similar to those in my program. So I guess the problem is ...

Milliseconds are set in the DateTime database and stored by ValidFrom / ValidTo, including Milliseconds. But I assume that the request does not include the millisecond part of the timestamp for any reason ... The requestTime variable, as ever, has milliseconds.

Unfortunately, I do not know how to check the actual values ​​sent in the request in order to verify this. I only know how to use items.toString () - a method for outputting generated SQL that contains placeholders.

I tried: 1. db.Log = Console.Out; which did not compile due to an error that "db.Log" would not be defined (also autocomplete did not offer "Log"). While db is derived from DbContext. 2. Also casting "objects" in ObjectQuery, and then using .ToTraceString () does not work, the program crashes at run time with an error message that the cast is invalid.

If this is important: I am using .NET 4.0 and EntityFramework.5.0.0.

Questions

  • How to register / output full SQL (including placeholder values)?
  • How to fix this problem in an elegant way? ... I do not mean a hack that simply subtracts a second from the "time" that is assigned to "ValidTo" in inValidate ()!

Yours faithfully,

Stephen

EDIT (more information)

I checked what happens with the SQL profiler, which seems fine. Timestamps with high (7 characters) prefixes are delivered correctly upon request. BUT: I do not get SELECT, causing the wrong result. So I guessed: it must be some kind of caching. So I set db.SaveChanges(); immediately before my LINQ request. Now I have all the requests in the profiler.

I tried the following code to change the data type in the database. As suggested by Slauma (see https://stackoverflow.com/a/165268/ ).

 modelBuilder.Entity<Item>().Property(f => f.ValidFrom) .HasColumnType("datetime2").HasPrecision(3); modelBuilder.Entity<Item>().Property(f => f.ValidTo) .HasColumnType("datetime2").HasPrecision(3); 

I reset the whole database before rebooting ...

Result: Successfully use HasPrecision (x); where x is one of 0, 3; (with or without db.SaveChanges () immediately before); BUT: x = 7 works with db.SaveChanges (); just before the request ...

So unfortunately this problem still exists ...

Current workaround

I apply the following method to any DateTime value before assigning it to a property of database objects. It simply rounds the precision of the DateTime to a full second (which I configured in the database). This also applies to any DateTime used to compare time.

Result: this is more of a hack than a solution! I will need to write access functions for all setter methods, so direct assignment cannot happen by accident.

  public static DateTime DateTimeDBRound(DateTime time) { DateTime t = time; long fraction = (t.Ticks % TimeSpan.TicksPerSecond); if (fraction >= TimeSpan.TicksPerSecond / 2) { t = t.AddTicks(TimeSpan.TicksPerSecond - fraction); } else { t = t.AddTicks(-fraction); } return t; } 
+8
datetime sql-server-2008 compare entity-framework-5 entity-framework
source share
1 answer

Question 1 How to maintain / output full SQL (including placeholder values)? I think the best way is SQL Server profiler. It displays all statements and meanings. Or http://www.hibernatingrhinos.com/products/EFProf

I do not know any other way to extract executable commands.

0
source share

All Articles