实体框架插入失败,带有日期列

时间:2014-03-26 08:58:47

标签: entity-framework date datetime

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

  

列(TypeName =“Date”)

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。我想,这应该是DATE。 如果有任何时间部分,则此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; }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我在bug #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. 在将值发送到数据库之前截断内存中的值。
  4. 希望这有帮助, 迭