2

是否可以使用 Entity Framework 6 的新依赖模式注入自定义映射规则?

我正在使用的数据库将一天中的时间存储在几time(0)列中。

根据 MSDNtime数据类型定义了特定的“一天中的时间”,而不是任意长度的时间。类型的范围从time00:00:00.0000000 到 23:59:59.9999999 证明了这一点。

一切都很好。但是,实体框架拒绝将其映射到DateTime属性。

到 ADO.NET 默认值的映射TimeSpan远非理想(正如Jon Skeet 指出的那样),因为 SQL Servertime不是任意时间跨度,而是具有 AM/PM 上下文。.NET 的TimeSpan格式化程序没有 AM/PM 的概念。time并且TimeSpan用于单独的问题域。从纯粹理想主义的角度来看,我宁愿总是映射timeDateTime. 这也是有道理的,因为固定的起点是一天中的某个时间。

更糟糕的是,由于 和 的这些单独的问题域timeTimeSpan像 DevExpress 的 TimeEdit 这样的控件只会绑定到DateTime属性。我希望避免使用简单地在TimeSpan和之间转换的重复属性弄脏我的所有实体DateTime

(这里的作者问了同样的问题,但要求较少: SQL 'time' type in Entity Framework Code First

4

1 回答 1

2

您的问题看起来非常类似于此页面上用于更改 DateTimes 约定的示例: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());
}

编辑只需重新阅读您的问题,我发现您希望在 C# 代码中使用 DateTime 并在数据库中使用 time(0) 而不是相反,这样就行不通了。不幸的是,我怀疑您将需要 2 个字段,例如此解决方案在映射时转换值- 这确实使数据库属性保持私有。

自定义编码约定的原始想法如何,但基于命名约定:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>()
                .Where(p => p.Name.EndsWith("TimeOfDay"))
                .Configure(p => p.HasColumnType("time(0)"));
}

编辑 2 因为这是一个无效的映射,所以我们别无选择:

在模型中:

private string DBTimeOfDay { get; set; }

[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public DateTime TimeOfDay
{
    get { return new DateTime(DBTimeOfDay.Ticks); }
    set { DBTimeOfDay= value.TimeOfDay; }
}

在 Context 类中:

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

另一种选择是创建一个在其 sql 中转换time(0)为的数据库视图DateTime,并映射到修改后的存储过程以进行更新。该技术已被建议用于不受支持的数据类型

编辑 3! 睡过这个......这是我的想法。

time(0) 表示一天中的某个时间。

Entity Framework 已选择将其转换为Timespan.

Timespans 应该代表持续时间。

Timespans很容易添加到DateTimes 中,结果是一个新的DateTime

C# 没有TimeOfDay数据类型

因此,在您的业务逻辑中,您必须将一天中的时间保持为TimeSpan永远不会超过 24 小时的时间,或者作为DateTime您将日期部分设置为任意值的位置,然后您将忽略该值。

EF 与 C# 一致,其中DateTime.TimeOfDay返回时间跨度

如果您在业务逻辑中进行任何算术运算,例如定期约会等,那么我认为 TimeSpan 实际上可能有一个稍强的论据。如果它很复杂,那么也许你应该开始使用野田时间

当它移动到 UI 时,问题就来了。TimeEdit需要一个DateTime......我们想将它显示为上午/下午......

这就是我将它映射到DateTime 的地方,即在UI 中。我正在使用 MVC。我正在使用视图模型。我已经从实体映射。我正在使用 AutoMapper。这很容易,并且可以保持实体的清洁。TimeSpan域中的属性转换DateTime为 UI ..

于 2013-11-13T15:17:32.867 回答