Reputation: 1675
I'm working to move our model over to EF Core and I'm having trouble finding a way to call the following code:
InitializeTime = context.ExecuteSqlCommand<DateTime>("SELECT CURRENT_TIMESTAMP FROM DUAL").FirstOrDefault();
We use the database time to synchronize everything but from what I can find calling raw sql outside a DbSet isn't available and the return type is restricted to the DbSet
type argument.
I was looking around and found that there are DbQuery
objects (Article) but that seems like heavy lifting just to get the current system date time.
Has anyone else come across this and found a easier solution?
Note: this is a desktop application so the code would be running client side and the system date time isn't reliable.
Upvotes: 3
Views: 3919
Reputation: 1675
In case anyone runs into the same issue. I ended up with the following:
Create a new class containing a DateTime
property
public class SystemDateTime
{
/// <summary>
/// System datetime from the server.
/// </summary>
public DateTime DateTime { get; set; }
}
Add a DbSet
of type SystemDateTime
to the Model
/// <summary>
/// Set for getting the current date time from the database.
/// </summary>
public DbSet<SystemDateTime> SystemDateTimes { get; set; }
Note: In EFCore 3.1 it needs to be of type DbSet
but in EFCore 2.? there is a different type devoted to this kind of set called DbQuery
. See the article Here.
Add the mapping to the model builder
modelBuilder.Entity<SystemDateTime>().HasNoKey();
modelBuilder.Entity<SystemDateTime>().Property<DateTime>(x => x.DateTime).HasColumnName(@"DateTime").HasColumnType(@"TIMESTAMP").IsRequired().ValueGeneratedNever();
Use DbSet
's FromSqlRaw
to query the database
List<SystemDateTime> systemDateTime = context.SystemDateTimes.FromSqlRaw("SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS') \"DateTime\" FROM DUAL").ToList();
This will return a list of one element so use First()
or Single
to get the value needed.
Upvotes: 2
Reputation: 3193
The EFCore namesakes context.Database.ExecuteSqlRaw(sql)
/context.Database.ExecuteSqlRInterpolated(sql)
(or context.Database.ExecuteSqlCommand(sql)
prior to EFCore 3, you haven't specified what version you're working with) can only return an int
, the number of rows affected by executing the sql statement.
context.Query<TQuery>()
(up to EFCore 3, deprecated from EFCore 3 onwards) or a keyless entity (EFCore 3 onwards) backed by an ordinary POCO are your options as far as I am aware if you want to use EFCore to execute the query.
Keyless Entity Types doco:
Usage scenarios
Some of the main usage scenarios for keyless entity types are:
Serving as the return type for raw SQL queries.
In terms of the overhead, it's not really when you think in terms of the unit of work/repository pattern that EFCore implements; it essentially forces you to implement a repository rather than have ad-hoc queries around the place.
Upvotes: 6