如何映射`时间(0)``来与DateTime`实体框架6实体、框架、时间、DateTime

2023-09-04 03:44:10 作者:ぅ少年追梦

有什么办法自定义映射规则,可以用实体框架6的新模式的依赖注入?

Is there any way a custom mapping rule could be injected using Entity Framework 6's new dependency pattern?

我有工作的数据库有一天存放在几个时间的次数(0)列。

The database I am working with has times of day stored in a few time(0) columns.

根据MSDN ,在时间数据类型定义一个特定的“的一天的时间的&rdquo ;,而不是任意的的时间长度的。这是通过的时间类型的范围内,00证明:00:00.0000000到23:59:59.9999999

According to MSDN, the time data type defines a particular “time of a day”, as opposed to an arbitrary length of time. This is evidenced by the range of the time type, 00:00:00.0000000 through 23:59:59.9999999.

一切都很好在这里。然而,实体框架拒绝它映射到的DateTime 属性。

All is well here. However, Entity Framework refuses to map it to a DateTime property.

映射到时间跨度的ADO.NET默认很不理想(如的乔恩斯基特指出),因为SQL Server的时间不是任意的时间跨度,但有AM / PM方面。 .NET的时间跨度格式具有AM / PM的概念。 时间时间跨度是独立的问题领域。从一个纯粹的理想主义一点,我宁愿永远地图时间的DateTime 。这也使得由于固定起点作为一天的时间的感

The mapping to the ADO.NET default of TimeSpan is far from ideal (as Jon Skeet pointed out) because SQL Server's time is not an arbitrary span of time but has AM/PM context. .NET's TimeSpan formatter has no concept of AM/PM. time and TimeSpan are for separate problem domains. From a purely idealistic point of view, I would rather always map time to DateTime. That also makes sense because of the fixed starting point as a time of day.

因为时,这些独立的问题领域糟糕的是,时间跨度,像DevEx preSS的TimeEdit控制只绑定到的DateTime 属性。我希望能避免弄脏我所有的实体复制的特性,简单地时间跨度的DateTime

Worse, because of these separate problem domains of time and TimeSpan, controls like DevExpress's TimeEdit will only bind to DateTime properties. I am hoping to avoid dirtying all my entities with duplicated properties that simply translate between TimeSpan and DateTime.

(笔者在这里问同样的问题,但有较少的要求: SQL'时间'类型的实体框架$ C C首先$ )

(The author here asked the same question but had fewer requirements: SQL 'time' type in Entity Framework Code First)

推荐答案

您的问题看起来很喜欢用来改变约定本页DateTime是否例子:的自定义code首先约定(EF6起)

Your problem looks very like the example used to change the convention for DateTimes on this page: Custom Code First Conventions (EF6 onwards)

这样的事情也许是:

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());
}

修改只需重读你的问题,我看你想要的DateTime在C#code和时间(0)数据库而不是相反的方式,这样不会工作。不幸的是,我怀疑你将需要2场这样的解决方案转换值时的映射 - 这确实让数据库私有财产

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)"));
}

编辑2     而且,由于这是一个无效的映射,它留给我们别无选择:

EDIT 2 And since that is an invalid mapping that leaves us with little choice:

在型号:

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");
   });
}

另一种选择是创建转换成数据库视图时间(0)的DateTime 在SQL和映射到修改过的存储过程进行更新。该技术已经被建议用于不支持的数据类型

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

修改3! 已经睡在这......这里是我的想法。

EDIT 3 ! Having slept on this...here are my thoughts.

时间(0)重新presents一天的时间。

time(0) represents a time of day.

实体框架已经选择将其转换为一个时间跨度

Entity Framework has chosen to convert it to a Timespan.

时间跨度,则应该重新present持续时间。

Timespans are supposed to represent durations.

时间跨度 s的结果是一个新的日期时间

Timespans are easily added to DateTimes with the result being a new DateTime

C#不具有的TimeOfDay 数据类型

因此​​,在你的业务逻辑,要么你一定要挺住一天中的时间为时间跨度,从来没有超过24小时,或为日期时间,你已经设置的日期部分为任意值,你则可以忽略。

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是用C#,其中 DateTime.TimeOfDay 返回时间跨度一致

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

当它移动到UI的问题就来了。 TimeEdit 需要的DateTime ...我们想将其显示为AM / PM ..

The problem comes when it moves to the UI. TimeEdit needs a DateTime...We want to display it as a.m./p.m...

所以这就是我将其映射到一个日期时间,即在用户界面中。我使用MVC。我使用的ViewModels。我已经从实体映射。我使用AutoMapper。它很容易与它保持实体清洁。 时间跨度在域属性转换为的DateTime 的用户界面。

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..