【问题标题】:Entity Framework insert failed with date column实体框架插入失败,日期列
【发布时间】:2014-05-04 13:13:22
【问题描述】:

如果将 DateTime 属性注释为 Date 类型,我遇到了 Entity Framework (V 6.1.0) 的问题:

列(TypeName = "日期")

public class MyTable
{
    [DatabaseGenerated]
    public Guid Id { get; set; }

    [Key, Column(TypeName = "Date"), DataType(DataType.Date)]
    public DateTime DateKey { get; set; }

    [Required]
    public string SomeProperty { get; set; }
}

我在 SQL 中的表的列被正确地创建为 DATE 列。

现在,如果我尝试插入一个新行并设置我的日期属性,例如使用 DateTime.Now() 我收到以下错误:

存储更新、插入或删除语句影响了意外 行数 (0)。实体可能已被修改或删除 实体已加载。刷新 ObjectStateManager 条目。

问题出在 EF 生成的 SQL 代码中:

exec sp_executesql N'
INSERT [dbo].[MyTable]([DateKey], [SomeProperty]) VALUES (@0, @1)

    SELECT [Id] FROM [dbo].[MyTable]
    WHERE @@ROWCOUNT > 0 AND [DateKey] = @0',

        N'@0 datetime2(7), @1varchar(max)',

        @0='2014-03-26 08:58:07', 
        @1='abcdef'

DateKey 的参数声明为 DATETIME2。我想,这应该是日期。 如果有任何时间部分,则此 select 语句不能返回任何行。如果我将参数 @0 更改为 DATE(因为它在我的模型中进行了注释,即使仍然包含时间部分,我也不会收到错误。

这是 EF 中的错误吗?

问候, 丹尼尔

编辑: 我不知道这是否与我的问题有关。我在 OnModel 中将我的所有日​​期列默认设置为 DATETIME2:

modelBuilder.Properties().Configure(p => p.HasColumnType("datetime2"));

编辑于 2014-03-27 提供完整的重现:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace EFDateColumnAsKey
    {
    class Program
    {
        static void Main(string[] args)
        {
            MyContext ctx = new MyContext();

            ctx.CalendarItems.Add(new CalendarItem() { StartDate = DateTime.Now.Date });        // This works
            ctx.SaveChanges();

            ctx.CalendarItems.Add(new CalendarItem() { StartDate = DateTime.Now });     // This not !!
            ctx.SaveChanges();

            ctx.Dispose();
        }

        public class MyContext : DbContext
        {
            public DbSet<CalendarItem> CalendarItems { get;set; }
        }


        public class CalendarItem
        {
            [DatabaseGenerated( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
            public int Id { get; set; }

            [Key, Column(Order = 1), DataType(DataType.Date)]
            public DateTime StartDate { get; set; }
        }
    }
}

【问题讨论】:

  • 昨天我读到一个包含完全相同错误的问题。如果您使用分离的上下文,似乎最有可能发生此错误。你也有这种情况吗?
  • 不,我不使用分离的对象。
  • 我在 codeplex 上开了一张票:(entityframework.codeplex.com/workitem/2185)

标签: entity-framework date datetime


【解决方案1】:

我在错误#2185 中添加了一些细节。总之,当我们为 INSERT 操作创建一个 SqlCommand 时,我们为 System.DateTime 类型的任何属性定义了一个 DATETIME2 类型的参数,但是出于兼容性原因,当我们默认创建数据库模式时,我们将创建一个 DATETIME 类型的列。

我们为插入生成的 SQL 如下所示:

INSERT [dbo].[CalendarItems]([StartDate]) VALUES (@0);
SELECT [Id] FROM [dbo].[CalendarItems] WHERE @@ROWCOUNT > 0 AND [StartDate] = @0; 

当您将任意 System.DataTime 实例作为 DATETIME2 参数传递时,最低有效位将被保留,但只要 DATETIME2 参数的值存储在 DATETIME 列中,该值就会被截断。

由于 StartDate 中存储的值不再与参数 @0 的值匹配,第二条语句(即我们用来检测受影响行的 SELECT 查询)将返回零行,命令将失败,事务将回滚等。

正如您已经发现的,可能的解决方法是:

  1. 使用代理标识键而不是声明 DateTime 类型的键
  2. 对列使用 DateTime2
  3. 在将值发送到数据库之前截断内存中的值。

希望这会有所帮助, 迭戈

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多