Open
Description
Using the current latest Oracle.EntityFrameworkCore (5.21.3), I think there's a bug using TIMESTAMP WITH LOCAL TIME ZONE columns. Oracle.ManagedDataAccess expects to use CLR type DateTime, but Oracle.EntityFrameworkCore requires DateTimeOffset. I think DateTime with kind set to Local is the most appropriate CLR type match.
If I use DateTime, I get the following error when creating code first migrations or querying.
The property 'Event.OccurredAt' is of type 'DateTime' which is not supported by the current database provider.
Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using
'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
If I use DateTimeOffset, I can create code first migrations, but I get the following error on query.
System.InvalidCastException
HResult=0x80004002
Message=Specified cast is not valid.
Source=Oracle.ManagedDataAccess
StackTrace:
at Oracle.ManagedDataAccess.Client.OracleDataReader.GetDateTimeOffset(Int32 i)
...
Here's a sample program:
class Program
{
public static void Main()
{
var id = CreateEvent("TestStarted");
Console.WriteLine($"Event saved with ID: {id}");
var @event = GetEvent(id);
Console.WriteLine($"Event fetched:\r\n{JsonSerializer.Serialize(@event)}");
Console.WriteLine("Test complete...");
}
private static Guid CreateEvent(string eventName)
{
var db = new MyContext();
var @event = new Event(eventName);
db.Events.Add(@event);
db.SaveChanges();
return @event.Id;
}
private static Event GetEvent(Guid id)
{
var db = new MyContext();
return db.Events.Find(id); //InvalidCast occurs here with DateTimeOffset
}
}
public class Event
{
public Event(string eventName) => EventName = eventName;
public Guid Id { get; private set; } = Guid.NewGuid();
public string EventName { get; private set; }
public DateTimeOffset OccurredAt { get; private set; } = DateTimeOffset.Now;
}
public class MyContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseOracle("sandbox connection string");
}
public DbSet<Event> Events { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Event>().Property(x => x.Id).HasColumnType("RAW(16)").IsRequired().ValueGeneratedNever();
modelBuilder.Entity<Event>().Property(x => x.EventName).HasColumnType("VARCHAR2").HasMaxLength(100).IsRequired().ValueGeneratedNever();
modelBuilder.Entity<Event>().Property(x => x.OccurredAt).HasColumnType("TIMESTAMP WITH LOCAL TIME ZONE").IsRequired().ValueGeneratedNever();
modelBuilder.Entity<Event>().HasKey(x => x.Id);
}
}