EntityFramework6.Npgsql icon indicating copy to clipboard operation
EntityFramework6.Npgsql copied to clipboard

DateTimeOffset LTE vs RawSql strange effects

Open roji opened this issue 9 years ago • 10 comments

From @tryhp3 on March 18, 2015 10:42

I think that TimeStampTZ <-> DateTimeOffset does not always work.

I have simple enttity:

public class Customer
{
        [Key]
        [Required]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]       
        public int Id { get; set; }

        public DateTimeOffset? DateCreated { get; set; }

        //other fields       
}

When I call Linq To Entities (Find method) first, and next SQL this work ok (I think that there is a cache): bez tytulu

When I call SQL first i have error: bez tytulu2

Additional information: The 'DateCreated' property on 'Customer' could not be set to a 'System.DateTime' value. You must set this property to a non-null value of type 'System.DateTimeOffset'.

Copied from original issue: npgsql/npgsql#542

roji avatar May 12 '16 12:05 roji

From @Emill on March 22, 2015 14:47

What is IRepository? It would be helpful if you could reduce the code so it only uses Entity Framework and Npgsql directly.

roji avatar May 12 '16 12:05 roji

From @tryhp3 on March 23, 2015 9:55

No problem:

    //CREATE TABLE "Contractors"
    //(
    //  "Id" integer NOT NULL,
    //  "DateCreated" timestamp with time zone,
    //  CONSTRAINT "Contractors_pkey" PRIMARY KEY ("Id")
    //)

    class Program
    {
        static void Main(string[] args)
        {
            using(var context = new DTOContext())
            {
                Contractor noWork = context.Contractors
                    .SqlQuery("select * from \"Contractors\" where \"Id\" = 1")
                            .Single();

                Contractor work = context.Contractors.Find(1);    
            }
        }
    }

    [Table("Contractors", Schema = "public")]
    public class Contractor
    {
        [Key]           
        public int Id { get; set; }

        public DateTimeOffset? DateCreated { get; set; }
    }

    public class DTOContext : DbContext
    {
        public DbSet<Contractor> Contractors { get; set; }
    }

przechwytywanie

roji avatar May 12 '16 12:05 roji

From @j-hogue on September 2, 2015 21:17

Any progress on this yet?

roji avatar May 12 '16 12:05 roji

From @Emill on September 2, 2015 21:28

I'm afraid not. This is a hard one. in Npgsql a timestamptz is normally mapped to a DateTime, but a DateTimeOffset in EF. In normal EF query generation, we have control over data types but not when you do it that way...

roji avatar May 12 '16 12:05 roji

@Emill, interestingly I'm working on the same area in EF7 at the moment. They make it possible to select a reading strategy that uses NpgsqlDataReader.GetFieldValue<T>() rather than doing NpgsqlDataReader.GetValue() and casting - which seems like the ideal solution to this problem (since Npgsql's Int16Handler supports returning bytes).

roji avatar May 12 '16 12:05 roji

@roji Wouldn't it generally be more correct to use a DateTimeOffset for timestamptz columns because otherwise you're throwing data away? This is already being done in EF as you mentioned. What motivation is there to use DateTime instead?

Correction: Apparently @Emill originally mentioned that but I assume any project maintainer should also know the motivation.

meoblast001 avatar May 29 '19 14:05 meoblast001

@meoblast001 which data is being thrown away?

Emill avatar May 29 '19 18:05 Emill

@meoblast001 note that PostgreSQL timestamptz does not contain a time zone or an offset - only a timestamp. timestamptz only makes PostgreSQL perform timezone conversions when reading/writing values based on your connection session's timezone setting.

PS Nice to see you again @Emill :)

roji avatar May 30 '19 00:05 roji

Thanks @roji. I wasn't aware of that. So it seems then that no persisted data is discarded. Defaulting to DateTimeOffset would probably only be interesting when reading the data then. I think I understand the motivation to use DateTime instead then.

meoblast001 avatar May 31 '19 09:05 meoblast001

If anyone still wondering on how to fix this, just add a annotation to your mapped entity:

[Column(TypeName = "timestamp with time zone")]
public DateTimeOffset MyUtcProperty { get; set; }

That works on ef6 but careful: you can only manage Offset-0 DateTime's with this configuration since postgres does not save the utc data on the column, just the defined datetime as timestamp, as mentioned here: Npgsql.org - Date and Time Handling - "Npgsql also supports reading and writing DateTimeOffset to timestamp with time zone, but only with Offset=0."

gersonmoreira avatar Mar 11 '24 20:03 gersonmoreira