【问题标题】:Datetime type mismatch trying to publish a SQL CLR database尝试发布 SQL CLR 数据库的日期时间类型不匹配
【发布时间】:2017-12-17 09:09:23
【问题描述】:

我正在尝试建立一个旧的解决方案,该解决方案将许多 .net 函数发布到 SQL Server 数据库。但是尝试发布到新数据库的操作在操作日期的功能上失败了。

失败的函数是:

[SqlFunction(TableDefinition="localtime datetime2", IsDeterministic=true, IsPrecise=true,
             DataAccess=DataAccessKind.None,
             SystemDataAccess=SystemDataAccessKind.None)]
public static DateTime ConvertFromUTC(DateTime utctime, string timezoneid)
{
    if (utctime.Kind == DateTimeKind.Unspecified)
        utctime = DateTime.SpecifyKind( utctime, DateTimeKind.Utc );

    utctime = utctime.ToUniversalTime();

    return TimeZoneInfo.ConvertTimeBySystemTimeZoneId( utctime, timezoneid );
}

我在尝试发布时收到的错误消息是:

正在创建 [dbo].[ConvertFromUTC]...

(268,1):SQL72014:.Net SqlClient 数据提供者:

消息 6551,级别 16,状态 2,过程 ConvertFromUTC,第 1 行
“ConvertFromUTC”的 CREATE FUNCTION 失败,因为返回值的 T-SQL 和 CLR 类型不匹配。

(268,0): SQL72045: 脚本执行错误

从 .net 生成的 SQL 以尝试添加函数:

CREATE FUNCTION [dbo].[ConvertFromUTC]
    (@utctime DATETIME, @timezoneid NVARCHAR (MAX))
RETURNS TABLE ([localtime] DATETIME2 (7) NULL)
AS EXTERNAL NAME [database].[IntelligentTutor.Database.Functions].[ConvertFromUTC]

现有数据库中函数版本的 SQL 定义(这证实了@MattJohnson 关于需要修复的方式是正确的):

CREATE FUNCTION [dbo].[ConvertFromUTC]
    (@utctime [datetime], @timezoneid [nvarchar](4000))
RETURNS [datetime] WITH EXECUTE AS CALLER
AS EXTERNAL NAME [database].[IntelligentTutor.Database.Functions].[ConvertFromUTC]

【问题讨论】:

  • 除了@Matt 的回答中提到的建议,您还应该考虑以下几点:从属性中删除TableDefinition="localtime datetime2",;使用SqlString 而不是string 代替timezoneid(这需要将return 中的timezoneid 更改为timezoneid.Value);并将@timezoneidNVARCHAR(MAX) 更改为NVARCHAR(50) 或任何有意义但不是MAX 的大小。另外,请注意TimeZoneInfo 类存在内存泄漏,这就是它要求将程序集标记为UNSAFE 的原因。
  • 有关一般使用 SQLCLR 的更多信息,请参阅我在 SQL Server Central 上写的关于此主题的系列:Stairway To SQLCLR(需要免费注册才能阅读其内容,但值得)。
  • @srutzky - HostProtectionAttribute.MayLeakOnAbort 并不意味着“有内存泄漏”。
  • @MattJohnson 感谢您提供该链接。所以只是意味着“可以泄漏,如果中止”,对吗?如中,如果允许成功完成不会泄漏?
  • 对。这是极不可能的事件。甚至有人会争辩说,这个特定的类不需要该属性,尽管现在对此无能为力。

标签: c# .net sql-server sqlclr


【解决方案1】:

SQL 函数与 .NET 方法签名不匹配。使其匹配:

  1. 在函数定义中将@utctime的类型改为DATETIME2,而不是DATETIME

  2. 将返回类型更改为仅RETURNS DATETIME2,而不是返回具有可为空的 datetime2 列的表。

另外,请注意,如果您使用的是 SQL 2016 或更高版本,或者使用的是 Azure SQL DB,则不需要此函数,因为您现在可以改用 AT TIME ZONE

【讨论】:

  • 在我考虑开始应用十几年的跳过代码现代化。我目前使用的是旧的 .net/sql 服务器配对吗?还是我需要更深入地爬进兔子洞,试图弄清楚发生了什么。
  • @DanNeely 您在问题中发布的代码不可能奏效。返回表的唯一方法是 .NET 中的返回类型是否为 IEnumerable。而且我认为如果没有在 SqlFunction 属性中注明 FillRowMethod,您将无法传回表格。这是马特在这个答案中提到的两个项目的补充(这是完全正确的,顺便说一句,所以+1)。
  • 对。它不会起作用,因为 .net 代码返回一个值,而您的 SQL 包装器需要一个表。标量值函数不同于表值函数。 Read here.
  • 好的。我有现有站点生产数据库的备份。有没有办法查看发布到的任何内容,以便我可以确保我对 C# 所做的任何修复都对应于之前的开发人员实际上设法以某种方式进入系统的任何内容?
猜你喜欢
  • 1970-01-01
  • 2019-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 2023-03-23
  • 1970-01-01
  • 2022-11-18
相关资源
最近更新 更多