Your problem looks very like the example used to change the convention for DateTimes on this page: Custom Code First Conventions (EF6 onwards)
Something like this perhaps:
public class TimeSpanConvention : Convention
{
public TimeSpanConvention()
{
this.Properties<TimeSpan>()
.Configure(c => c.HasColumnType("datetime"));
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new TimeSpanConvention());
}
EDIT Just re-read your question, and I see that you want DateTime in the C# code and time(0) in the database not the other way around so that won't work. Unfortunately, I suspect you will need 2 fields like this solution Convert value when mapping - which does keep the database property private.
What about the original idea of a custom coding convention but based on a naming convention:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<DateTime>()
.Where(p => p.Name.EndsWith("TimeOfDay"))
.Configure(p => p.HasColumnType("time(0)"));
}
EDIT 2
And since that is an invalid mapping that leaves us with little choice:
In the Model:
private string DBTimeOfDay { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public DateTime TimeOfDay
{
get { return new DateTime(DBTimeOfDay.Ticks); }
set { DBTimeOfDay= value.TimeOfDay; }
}
And in the Context class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ modelBuilder.Types().Configure(c =>
{
var properties = c.ClrType.GetProperties(BindingFlags.NonPublic
| BindingFlags.Instance)
.Where(p => p.Name == "DBTimeOfDay");
foreach (var p in properties)
c.Property(p).HasColumnName("TimeOfDay");
});
}
Another option is to create a database view that converts time(0)
to DateTime
in its sql, and map to modified stored procedures for updates. That technique has been suggested for unsupported data types
EDIT 3 !
Having slept on this...here are my thoughts.
time(0) represents a time of day.
Entity Framework has chosen to convert it to a Timespan
.
Timespan
s are supposed to represent durations.
Timespans
are easily added to DateTime
s with the result being a new DateTime
C# does not have a TimeOfDay
data type
So in your business logic either you have to hold time of day' as a TimeSpan
that never exceeds 24 hours or as a DateTime
where you have set the date part to an arbitrary value that you then ignore.
EF is consistent with C# where DateTime.TimeOfDay
returns a Timespan
If you are doing any arithmetic in the business logic, say for recurring appointments or such, then I think there may actually be a marginally stronger argument for TimeSpan. If it's complicated then maybe you should start using Noda time
The problem comes when it moves to the UI. TimeEdit
needs a DateTime
...We want to display it as a.m./p.m...
So that is where I would map it to a DateTime i.e. in the UI. I'm using MVC. I'm using ViewModels. I'm already mapping from Entities. I'm using AutoMapper. It's easy and it keeps the Entities clean. TimeSpan
properties in the Domain converted to DateTime
for UI..