【问题标题】:How to map `time(0)` to `DateTime` with Entity Framework 6如何使用 Entity Framework 6 将`time(0)` 映射到`DateTime`
【发布时间】:2013-11-26 06:02:36
【问题描述】:

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

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

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

这里一切顺利。但是,Entity Framework 拒绝将其映射到 DateTime 属性。

到 ADO.NET 默认值 TimeSpan 的映射远非理想(如 Jon Skeet pointed out),因为 SQL Server 的 time 不是任意时间跨度,而是具有 AM/PM 上下文。 .NET 的 TimeSpan 格式化程序没有 AM/PM 的概念。 timeTimeSpan 用于不同的问题域。从纯粹理想主义的角度来看,我宁愿总是将time 映射到DateTime。这也是有道理的,因为起点是一天中的某个时间。

更糟糕的是,由于timeTimeSpan 这两个独立的问题域,像 DevExpress 的 TimeEdit 这样的控件只会绑定到 DateTime 属性。我希望避免在 TimeSpanDateTime 之间转换的重复属性弄脏我的所有实体。

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

【问题讨论】:

    标签: .net sql entity-framework datetime


    【解决方案1】:

    您的问题与此页面上用于更改 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) ,而不是相反,这样就行不通了。不幸的是,我怀疑您将需要像此解决方案 Convert value when mapping 这样的 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,并映射到修改后的存储过程以进行更新。该技术已被建议用于unsupported data types

    编辑 3 ! 睡了……这是我的想法。

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

    Entity Framework 已选择将其转换为Timespan

    Timespans 应该代表持续时间。

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

    C# 没有 TimeOfDay 数据类型

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

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

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

    当它移动到 UI 时,问题就来了。 TimeEdit 需要 DateTime...我们希望将其显示为 a.m./p.m...

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

    【讨论】:

    • 我可能会弄脏数据库、实体或程序逻辑——但我希望有办法一开始就解决这个问题。
    • 如果流畅的映射有效,单独映射属性也不是问题。但是,运行时错误提示错误 2019:指定的成员映射无效。 'Edm.DateTime[Nullable=True,DefaultValue=,Precision=]' 类型与 'SqlServer.time[Nullable=True,DefaultValue=,Precision=7]' 不兼容
    • DateTime 在数据库中或在TimeSpanDateTime 之间转换的重复属性然后...
    • 任何人都可以阐明通过依赖关系修改 EF 的行为吗?
    猜你喜欢
    • 1970-01-01
    • 2022-12-30
    • 2017-12-31
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多