【问题标题】:Migrating from EF Core 2 to EF Core 3 - Datetime milliseconds precision从 EF Core 2 迁移到 EF Core 3 - 日期时间毫秒精度
【发布时间】:2020-01-07 08:55:40
【问题描述】:

我有一些迁移将一些数据插入到数据库中,这就是其中之一:

 migrationBuilder.InsertData(
            table: "TSegment",
            columns: new[] { "SegmentId", "CreatedOn", "ParentId", "SegmentType", "UpdatedOn" },
            values: new object[,]
            {
                { 1, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(4948), null, "YouAndYourFamily", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(5782) },
                { 2, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6649), 1, "AboutYou", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6658) },
                { 3, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6670), 1, "YourFamily", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6676) },
                { 4, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6679), 1, "Employment", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6685) },
                { 5, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6688), null, "HomeAndContact", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6694) },
                { 6, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6700), 5, "YourHome", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6703) },
                { 7, new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6709), 5, "ContactDetails", new DateTime(2019, 1, 22, 12, 24, 23, 48, DateTimeKind.Utc).AddTicks(6712) }
            });

将 EF Core 升级到版本 3 后,上面的代码会生成此插入:

IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
SET IDENTITY_INSERT [TSegment] ON;
INSERT INTO [TSegment] ([SegmentId], [CreatedOn], [ParentId], [SegmentType], [UpdatedOn])
VALUES (1, '2019-01-22T12:24:23.0484948Z', NULL, N'YouAndYourFamily', '2019-01-22T12:24:23.0485782Z'),
(2, '2019-01-22T12:24:23.0486649Z', 1, N'AboutYou', '2019-01-22T12:24:23.0486658Z'),
(3, '2019-01-22T12:24:23.0486670Z', 1, N'YourFamily', '2019-01-22T12:24:23.0486676Z'),
(4, '2019-01-22T12:24:23.0486679Z', 1, N'Employment', '2019-01-22T12:24:23.0486685Z'),
(5, '2019-01-22T12:24:23.0486688Z', NULL, N'HomeAndContact', '2019-01-22T12:24:23.0486694Z'),
(6, '2019-01-22T12:24:23.0486700Z', 5, N'YourHome', '2019-01-22T12:24:23.0486703Z'),
(7, '2019-01-22T12:24:23.0486709Z', 5, N'ContactDetails', '2019-01-22T12:24:23.0486712Z');
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
    SET IDENTITY_INSERT [TSegment] OFF;

我们可以看到,日期毫秒有 6 位小数,但如果我将 EF Core 降级到版本 2,相同的迁移会生成此插入:

IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
SET IDENTITY_INSERT [TSegment] ON;
INSERT INTO [TSegment] ([SegmentId], [CreatedOn], [ParentId], [SegmentType], [UpdatedOn])
VALUES (1, '2019-01-22T12:24:23.048', NULL, N'YouAndYourFamily', '2019-01-22T12:24:23.048'),
(2, '2019-01-22T12:24:23.048', 1, N'AboutYou', '2019-01-22T12:24:23.048'),
(3, '2019-01-22T12:24:23.048', 1, N'YourFamily', '2019-01-22T12:24:23.048'),
(4, '2019-01-22T12:24:23.048', 1, N'Employment', '2019-01-22T12:24:23.048'),
(5, '2019-01-22T12:24:23.048', NULL, N'HomeAndContact', '2019-01-22T12:24:23.048'),
(6, '2019-01-22T12:24:23.048', 5, N'YourHome', '2019-01-22T12:24:23.048'),
(7, '2019-01-22T12:24:23.048', 5, N'ContactDetails', '2019-01-22T12:24:23.048');
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
    SET IDENTITY_INSERT [TSegment] OFF;

由于 SQL Server 的精度为小数点后 3 位,我无法将所有日期时间列更改为 Datetime2,有人知道解决方法吗?

【问题讨论】:

  • 什么是表列类型?当列是datetime2(0)datetime2(3) 时,存储微秒是没有意义的。
  • 顺便说一句,你为什么要使用 ticks?你真的想节省微秒吗?在这种情况下,您必须使用适当的类型。 datetime 没有所需的精度。您必须使用 datetime2(7) 在列注释中指定该精度。即使这样,您也可以获得 100ns 的准确度
  • 这个问题看了两遍,一头雾水。如果你只想要 毫秒,那么使用刻度是没有意义的。事实上,EF Core 2 的截断应该被视为一个 bug - datetime doesn't even have millisecond precision。您可以获得.047.050。所有这些值都将作为.050 存储在数据库中。你有实际问题吗?或者您是否依赖错误的实现来获得 .047 而不是 .050

标签: sql-server ef-core-3.1 entity-framework-core-3.1


【解决方案1】:

您可以通过将其包装在 sqlDataTime 结构中来解决您的问题,例如:

new SqlDateTime (DateTime value) 

如果是 poco 对象:
您可以尝试使用这样的数据注释指定列类型

[Column(TypeName = "datetime")]
DateTime CreatedOn {get;set;}

docs

【讨论】:

  • 这无济于事。 OP 要存储的值不能使用datetime 存储,并将四舍五入为.047.050。即使.048 也会被舍入为.047。 EF Core 2 的截断其实是一个 bug
【解决方案2】:

嗯,问题不在于毫秒。我从迁移中删除了AddTicks 和毫秒:

  migrationBuilder.InsertData(
            table: "TSegment",
            columns: new[] { "SegmentId", "CreatedOn", "ParentId", "SegmentType", "UpdatedOn" },
            values: new object[,]
            {
                { 1, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), null, "YouAndYourFamily", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) },
                { 2, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), 1, "AboutYou", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc)},
                { 3, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), 1, "YourFamily", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) },
                { 4, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), 1, "Employment", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) },
                { 5, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), null, "HomeAndContact", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) },
                { 6, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), 5, "YourHome", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) },
                { 7, new DateTime(2019, 1, 22, 12, 24, 23, DateTimeKind.Utc), 5, "ContactDetails", new DateTime(2019, 1, 22, 12, 24, 23,DateTimeKind.Utc) }
            });

现在生成以下脚本:

IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
SET IDENTITY_INSERT [TSegment] ON;
INSERT INTO [TSegment] ([SegmentId], [CreatedOn], [ParentId], [SegmentType], [UpdatedOn])
VALUES (1, '2019-01-22T12:24:23.0000000Z', NULL, N'YouAndYourFamily', '2019-01-22T12:24:23.0000000Z'),
(2, '2019-01-22T12:24:23.0000000Z', 1, N'AboutYou', '2019-01-22T12:24:23.0000000Z'),
(3, '2019-01-22T12:24:23.0000000Z', 1, N'YourFamily', '2019-01-22T12:24:23.0000000Z'),
(4, '2019-01-22T12:24:23.0000000Z', 1, N'Employment', '2019-01-22T12:24:23.0000000Z'),
(5, '2019-01-22T12:24:23.0000000Z', NULL, N'HomeAndContact', '2019-01-22T12:24:23.0000000Z'),
(6, '2019-01-22T12:24:23.0000000Z', 5, N'YourHome', '2019-01-22T12:24:23.0000000Z'),
(7, '2019-01-22T12:24:23.0000000Z', 5, N'ContactDetails', '2019-01-22T12:24:23.0000000Z');
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'SegmentId', N'CreatedOn', N'ParentId', N'SegmentType', N'UpdatedOn') AND [object_id] = OBJECT_ID(N'[TSegment]'))
SET IDENTITY_INSERT [TSegment] OFF;

它仍然为毫秒生成 6 位小数,并且正在抛出这个异常:

Microsoft.Data.SqlClient.SqlException (0x80131904):转换失败 从字符串转换日期和/或时间时。在 Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException 异常, Boolean breakConnection, Action`1 wrapCloseInAction) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException 异常,布尔型 breakConnection,Action`1 wrapCloseInAction) 在 Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler、SqlDataReader 数据流、 BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean & dataReady) 在 Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(字符串 方法名,布尔 isAsync,Int32 超时,布尔 asyncWrite) 在 Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 完成, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName) at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery() 在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject 参数对象)在 Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection 连接,IReadOnlyDictionary`2 参数值)在 Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands,IRelationalConnection 连接)在 Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(字符串 目标迁移)在 Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade 数据库外观)在 IntelliFlo.Platform.EntityFramework.Database.Tasks.DatabaseMigrationTask.Run() 在 IntelliFlo.Platform.EntityFramework.Database.DatabaseInitializer.ExecuteTask(IDatabaseTask 任务)

我错过了什么吗?

【讨论】:

    猜你喜欢
    • 2022-01-15
    • 2021-11-23
    • 2018-08-15
    • 2022-11-11
    • 2020-09-09
    • 2021-11-22
    • 2018-10-02
    • 2018-06-19
    • 2021-03-21
    相关资源
    最近更新 更多