无法将空字符串传递到非空数据库字段

时间:2018-01-26 22:45:32

标签: sql-server delphi sql-server-2014 ado delphi-10-seattle

我很难接受一些非常直截了当的事情。我有一个SQL Server数据库,我正在尝试使用空字符串更新不可为空的varchar或nvarchar字段。我知道这是可能的,因为空字符串'' NULL相同。但是,使用TADOQuery,我不允许这样做。

我正在尝试像这样更新现有记录:

ADOQuery1.Edit;
ADOQuery1['NonNullFieldName']:= '';
//or
ADOQuery1.FieldByName('NonNullFieldName').AsString:= '';
ADOQuery1.Post; //<-- Exception raised while posting

如果字符串中有任何内容,即使只是一个空格,它也可以正常保存。但是,如果它是一个空字符串,它就会失败:

  

不可为空的列无法更新为Null。

但它不是空的。它是一个空字符串, 可以正常工作。我发誓我过去曾经多次通过空字符串。

为什么我会收到此错误,我该怎么做才能解决它?

其他详情:

  • 数据库:Microsoft SQL Server 2014 Express
  • 语言:Delphi 10 Seattle Update 1
  • 数据库驱动程序:SQLOLEDB.1
  • 字段正在更新:nvarchar(MAX) NOT NULL

2 个答案:

答案 0 :(得分:12)

我可以使用SS2014,OLEDB驱动程序和下面的代码重现您报告的问题 西雅图以及使用MAX创建表作为列大小和特定数字(在我的情况下为4096)时的行为差异。我以为我会发布这个作为替代方案 回答是因为它不仅展示了如何系统地研究这种差异 但也要确定为什么出现这种差异(以及将来如何避免这种差异)。

请参考并执行下面的代码,如所写的,即使用UseMAX定义 活性

开启&#34;使用调试DCU&#34;在执行代码之前的项目选项中,立即执行 揭示所描述的异常发生在Data.Win.ADODB第4920行

Recordset.Fields[TField(FModifiedFields[I]).FieldNo-1].Value := Data
TCustomADODataSet.InternalPost

和Debug评估窗口显示了这一点 此时DataNull

接下来,请注意

update jdtest set NonNullFieldName = ''

在没有投诉(Command(s) completed successfully.)的SSMS2014查询窗口中执行,所以似乎是 {49}行Data Null导致问题的原因是,&#34;为什么?&#34;

首先要注意的是表单的标题显示为ftMemo

接下来,注释掉UseMAX define,重新编译并执行。结果:没有例外 请注意,表单的标题现在显示为ftString

这就是原因:使用特定数字表示列大小意味着 RTL检索的表元数据导致客户端Field被创建 作为TStringField,您可以通过字符串赋值语句设置其值。

OTOH,当您指定MAX时,生成的客户端Field的类型为ftMemo, 这是Delphi的BLOB类型之一,当你分配时 对于ftMemo字段的字符串值,您受Data.DB.Pas中的代码的支配,它使用TBlobStream对记录缓冲区进行所有读取(和写入)操作。问题在于,据我所知,在经过大量实验和跟踪代码之后,TMemoField使用BlobStream的方式无法正确区分将字段内容更新为&#39;&#39;&#39;并将字段的值设置为Null(如System.Variants中所示)。

简而言之,每当您尝试将TMemoField的值设置为空字符串时,实际发生的情况是字段的状态设置为Null,这就是导致q中的异常的原因。 AFAICS,这是不可避免的,所以无论如何也没有明显的解决方法。

我没有调查ftMemoftString之间的选择是由Delphi RTL代码还是它所依赖的MDAC(Ado)层做出的:我希望它实际上由{ {1}} TAdoQuery使用。

QED。请注意,这种系统的调试方法已经揭示了这一点 问题&amp;原因是很少的努力和零试验和错误,这是 我在q的评论中试图提出的建议。

另一点是,这个问题可以完全没有被追踪 求助于服务器端工具,包括SMSS分析器。没有必要使用分析器来检查客户端发送到服务器的内容 因为没有理由认为服务器返回错误 不对。这证实了我在客户端开始调查所说的话。

此外,使用RecordSet ed Sql动态创建的表,通过简单观察应用程序的两次运行,可以在一个步骤中有效地隔离问题。

代码

IfDef

答案 1 :(得分:1)

在数据类型中使用MAX时会出现问题。 varchar(MAX)nvarchar(MAX)都利用此行为。删除MAX并将其替换为大号(例如5000)时,它会允许空字符串。