我有一个问题与实体框架(v6.1.0),如果一个DateTime属性被注释为日期类型:
Column(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(),我得到以下错误:
问题出在EF生成的SQL代码中:存储更新、插入或删除语句受意外影响行数(0)。实体可能被修改或删除实体被加载。刷新ObjectStateManager表项。
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中的一个bug吗?
问候,丹尼尔
编辑:我不知道这是否与我的问题有关。默认情况下,我在OnModelCreating中配置了所有日期列为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; }
}
}
}
我已经为bug #2185添加了一些细节。总之,当我们为INSERT操作创建SqlCommand时,我们为任何System类型的属性定义了一个DATETIME2类型的参数。但是出于兼容性原因,在默认情况下创建数据库模式时,我们将创建一个DateTime类型的列。
我们为插入生成的SQL如下所示:INSERT [dbo].[CalendarItems]([StartDate]) VALUES (@0);
SELECT [Id] FROM [dbo].[CalendarItems] WHERE @@ROWCOUNT > 0 AND [StartDate] = @0;
当你通过一个任意的系统。DataTime实例作为DATETIME2参数,最小有效数字将被保留,但是一旦DATETIME2参数的值存储在DATETIME列中,该值将被截断。
由于存储在StartDate中的值不再与参数@0的值匹配,第二条语句(即我们用来检测受影响的行的SELECT查询)将返回零行,命令将失败,事务将回滚,等等。
正如您已经发现的,可能的解决方法是:
- 使用代理身份键代替声明DateTime类型的键
- 对列 使用DateTime2
- 在发送到数据库之前截断内存中的值。
希望这有帮助,迭戈