实体框架7无法插入日期时间

debian entity-framework-core mono sql-server windows

我正在使用EntityFramework 7,beta7并具有以下实体:

C#

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

SQL

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

我执行以下操作:

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

这在Windows上是成功的,但在debian上的mono下失败了。相同的SQL服务器/数据库。生成的SQL如下。请注意为@p1呈现的类型和值的差异:

视窗

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

Linux上的失败是:

从字符串转换日期和/或时间时转换失败。

问题

  1. 为什么Windows产生datetime2时类型是明确设定datetime
  2. linux版本生成无效的SQL,因此失败。如何在mono / linux上插入datetime值?

一般承认的答案

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

  2. Mono使用TDS与sql服务器一起工作(基于FreeTDS ,它使用了相当过时的版本。这个版本不知道sql server的“datetime2”类型,所以不要升级到新版本的TDS(也许这太过分了)现在工作),实现了一种黑客攻击,将datetime2从\转换为字符串。现在,datetime2的精度高于datetime,所以将datetime2转换为string然后将该字符串转换为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
    

    你可以在这里阅读更多相关信息。

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

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



许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因