Entity Framework 7 fails to insert datetime

时间:2015-09-29 00:37:43

标签: sql-server windows mono debian entity-framework-core

I'm using EntityFramework 7, beta7 and have the following entity:

C#

public class Log
{
    [Column(TypeName ="datetime")]
    public DateTime Date { get; set; }
    ...
}

SQL

CREATE TABLE [dbo].[Logs] (
    [Date] [datetime] NOT NULL,
    ...
)

And I execute the following:

db.Logs.Add(new Log { Date = DateTime.UtcNow });
db.SaveChanges();

This is successful on Windows, but fails under mono on debian. Same SQL server/database. The SQL generated is below. Note the difference of the type and value rendered for @p1:

Windows

exec sp_executesql N'SET NOCOUNT OFF;
INSERT INTO [Logs] ([Browser], [Date], [Exception], [HostAddress], [Level], [Logger], [Message], [Thread], [Url], [Username])
OUTPUT INSERTED.[Id]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9);
',N'@p0 nvarchar(max) ,@p1 datetime2(7),@p2 nvarchar(max) ,@p3 nvarchar(max) ,@p4 nvarchar(4000),@p5 nvarchar(4000),@p6 nvarchar(4000),@p7 nvarchar(4000),@p8 nvarchar(max) ,@p9 nvarchar(max) ',@p0=NULL,@p1='2015-09-28 23:02:26.0367851',@p2=NULL,@p3=NULL,@p4=N'INFO',@p5=N'Fanatics.ConsoleApp.Program',@p6=N'Console app test',@p7=N'0',@p8=NULL,@p9=NULL
go

Linux

exec sp_executesql N'SET NOCOUNT OFF;
INSERT INTO [Logs] ([Browser], [Date], [Exception], [HostAddress], [Level], [Logger], [Message], [Thread], [Url], [Username])
OUTPUT INSERTED.[Id]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9);
',N'@p0 nvarchar(4000), @p1 char(27), @p2 nvarchar(4000), @p3 nvarchar(4000), @p4 nvarchar(4000), @p5 nvarchar(4000), @p6 nvarchar(4000), @p7 nvarchar(4000), @p8 nvarchar(4000), @p9 nvarchar(4000)',@p0=NULL,@p1='2015-09-28T23:03:21.5561720',@p2=NULL,@p3=NULL,@p4=N'INFO',@p5=N'Fanatics.ConsoleApp.Program',@p6=N'Console app test',@p7=N'0',@p8=NULL,@p9=NULL
go

The failure on Linux is:

Conversion failed when converting date and/or time from character string.

Questions

  1. Why does Windows generate a datetime2 when the type is explicitly set to datetime?
  2. The linux version is generating invalid SQL, hence the failure. How can I insert datetime values on mono/linux?

1 个答案:

答案 0 :(得分:8)

  1. .NET DateTime类型的范围比sql server" datetime"更广泛。类型。实际上,.NET DateTime与sql server" datetime2"的范围相同。类型,这就是为什么Entity Framework在将DateTime转换为sql日期时会在任何地方使用datetime2(如果可能)(如示例所示)。在这种情况下,表列的类型无关紧要。您可以阅读此design meeting notes,其中EF小组讨论了datetime和datetime2的问题,并决定将其保留原样(以及背后的原因)。

  2. Mono使用TDS与sql服务器一起使用(基于FreeTDS,它使用了相当过时的版本。这个版本不知道sql server" s" datetime2&# 34;键入,所以不是升级到新版本的TDS(也许现在工作太多了),实现了一种黑客攻击,将datetime2从\转换为字符串。现在,datetime2的精度高于datetime,所以在转换datetime2时字符串然后将该字符串转换为datetime(隐式完成)会导致您看到的错误。这很容易检查:

    select cast('2015-09-28T23:03:21.5561720' as datetime2) -- < all fine
    select cast('2015-09-28T23:03:21.5561720' as datetime) -- < error from your question
    

    您可以阅读更多相关信息here

  3. 您可能会问,是否可以在单声道上使用EF和sql server。好吧,您可以通过在EF模型中将ProviderManifestToken设置为2005来解决此问题。这将使EF与sql server 2005一起使用,并且它不会在任何地方使用datetime2。但是你会丢失在sql server 2005之后添加的其他类型,更不用说那是脏黑客。

    作为旁注 - 最好不要使用sql server对mono进行任何认真的开发。单声道的SQL服务器提供程序充满了bug,上面的bug是最无辜的。它有空值问题,连接池问题(这个问题非常严重 - 如果你在连接池连接上超时 - 这个连接将在整个生命周期内被破坏,并且该连接上的 ALL 查询将失败.Hack - 如果您的查询超时,则从连接池中删除连接)等等。大多数这些错误已知多年,并且仍未修复。如果你有选择 - 只需使用postgresql,它是免费的,好的,我在单声道上没有问题。