dbExpress /未指定密钥

时间:2012-04-12 10:49:02

标签: delphi delphi-7 firebird dbexpress

我正在使用dbExpress组件(Delphi 7)开发数据库程序。通过以下组件从数据库中检索数据:TSQLDataSet - > TDataSetProvider - > TClientDataSet - > TDatasource - > TDBEdit。到目前为止,表格已正常运作。 TSQLDataset中的查询是

select id, name, byteken, timeflag from scales where id = :p1

我在数据库表中添加了一个大的(2048)varchar字段;当我将此字段添加到上述查询(并将TDBMemo或TDBRichEdit连接到TDatasource)时,当我尝试编辑新文本字段中的值时,我收到以下消息

Unable to find record. No key specified.

当表单上没有TDBMemo时(但查询中包含varchar字段),我得到相同的错误。一旦从查询中删除varchar字段,一切都会再次正常工作。

这个问题的原因是什么?

====更多信息====

我现在已经在表单中定义了持久字段。保存表的键的字段的提供者标志设置为[pfInUpdate,pfInWhere,pfInKey],而所有其他字段的标志为[pfInUpdate,pfInWhere]。这并没有解决问题。

持久字段在clientdataset上定义。当我在TSQLDataSet上定义它们时,关于“没有指定密钥”的错误消息'没有发生。程序仍然会显示此错误消息(我之前忽略了这一点):

EDatabase error: arithmetic exception, numeric overflow or string truncation

大字符串字段在' displaywidth'中具有正确的值。和'尺寸'。

====更多信息====

我重写了表单以使用非数据感知组件。一个查询从数据库中检索数据(使用与我在TSQLDataSet中使用的查询字符串完全相同的查询字符串);然后将数据传输到控件。在用户按下表单上的“确定”按钮后,数据将通过执行更新或插入的另一个查询传递回数据库。由于这是正常的,我不知道数据感知组件的问题是什么。

====又一段信息====

我在Stack Overflow上发现了this question,似乎解决了类似的问题。我将查询更改为

select id, name, name, byteken, timeflag, 
cast (constext as varchar (2048)) as fconstext
from scales
where id = :p1

并将dbMemo的数据字段设置为&f; fconstext'。在向dbMemo添加文本后,' applyupdates'现在呼叫失败并显示以下消息

column unknown 'fconstext'

尽管存在使用该名称创建的持久字段。

我不知道这是否有助于或只是混淆水。

====更多信息,4月23日====

我从数据库表中删除了该字段,然后将其添加回来。只要输入到有问题的数据字段中的字符串少于约260个字符,所写的程序就可以正常工作。我一次添加十个字符几次没有问题,直到字符串长度为256.然后我添加了一些字符(不计数),试图保存 - 并得到错误。从现在开始,尝试添加甚至多一个字符会导致出现错误消息(来自clientdataset的' applyupdates'方法)。

最初,该字段包含832个字符,因此我可以成功存储的字符数没有硬限制。但是一旦出现错误消息,它就会出现,就像数据库记得存在错误一样。

====更多信息,4月24日====

再次,我从数据库中删除了字段,然后将其添加回来;字符集是WIN1251,原因我现在不清楚(我不需要西里尔字符)。无论字段本身如何定义,我可以使用数据感知控件输入的最大字符数似乎大约为280。

我已经开始在发生此问题的真实程序中使用非数据感知控件,我可以向您保证此限制不存在。因此,我很确定问题不是由于字符大小的不匹配,正如所建议的那样。不要忘记我使用的是Delphi 7,它没有unicode字符串。我认为其中一个组件有一个错误,但是当我使用旧版本时,我想问题已经解决了,但在我使用的版本中没有。

====希望最终编辑,25/04/12 ====

根据蚊子的建议,我创建了一个新的数据库,其默认字符集是WIN1252(UTF-8并不是一个选择,而且无论如何我的程序都不是unicode)。在这个干净的数据库中,我定义了一个表,其中' constext'字符串的字符集也被定义为WIN1252。我运行了有问题的表单的数据感知版本,并能够毫无问题地输入文本(目前超过1700个字符)。

因此,似乎问题是通过为数据库定义一个字符集而为字段定义一个字符集来创建的。我不知道如何检查数据库的默认字符集定义为什么,所以我无法确认。

我现在遇到了一个小问题:定义一个新数据库(有50多个表)并从原始数据库复制数据。由于这个数据库服务于客户的旗舰产品,我有点担心这样做....

2 个答案:

答案 0 :(得分:2)

检查提供商的UpdateMode属性。如果设置为upWhereChangedupWhereKeyOnly,则需要数据库表中的密钥才能正常工作。

答案 1 :(得分:1)

无法找到记录。没有指定密钥。

从ID =:p1

的比例设置选择ID,名称,字节,时间标志

从id = 245

的比例中选择id,name,byteken,timeflag

设计时的现有ID。


施放 cast(constext as varchar(2048))..... 如果更改了列的定义,则该列类型的现有CAST可能会变为无效

算术异常,数字溢出或字符串截断

  1. 字符串截断 当连接字符串不适合基础CHAR或VARCHAR数据类型大小时,会发生这种情况。如果结果进入表列,也许这是一个有效的错误。或者你真的需要增加列大小。类似地存储在存储过程或触发变量中的中间值

  2. 字符音译失败 当您将数据库中的数据存储在一个字符集中时会发生这种情况,但是对所需字符集的音译失败。存在字符集音译的各种点。有一个自动的: 您从数据库中检索的每一段数据(通过SELECT或其他方式)都会从数据库表格列的字符集音译为连接字符集。如果字符集太不相同,则会有两种翻译:首先是从列charset到Unicode,然后是从Unicode到连接字符集。 此外,您可以通过将列CASTing到另一个字符集来手动请求音译,例如: CAST(column_name AS varchar(100)字符集WIN1251)。 音译失败的原因只是某些字符集中不存在某些字符。例如,WIN1252不包含任何西里尔字符,因此如果您使用连接字符集WIN1252并尝试从具有西里尔字符的列中进行SELECT,则可能会出现此类错误。 在现代,最好在应用程序和UTF8连接字符中使用Unicode或UTF8。并确保至少使用 Firebird 2.0 ,支持UTF8。

  3. 使用DotNetFirebird 时参数的顺序错误 使用DotNetFirebird时将参数添加到FbCommand的顺序可能会导致-303异常,提示“算术异常,数字溢出或字符串截断”。参数的顺序必须符合存储过程中params的顺序 - 否则将抛出异常。示例(.NET,C#,DotNetFirebird(使用FirebirdSql.Data.FirebirdClient;))

    FbCommand CMD = new FbCommand(“TBLTEXT_ADDTEXT”,cnn); CMD.Parameters.Add(“TEXT1”,FbDbType.VarChar,600).Value = strText1; CMD.Parameters.Add(“TEXT2”,FbDbType.VarChar,600).Value = strText2; CMD.CommandType = CommandType.StoredProcedure; CMD.ExecuteNonQuery(); 如果过程“TBLTEXT_ADDTEXT”中的参数顺序与将参数添加到FbCommand-Object的顺序不同,则会收到-303错误。

  4. 4

      

    No'am Newman说 但是一旦出现错误消息,它就会出现,就好像   数据库记住存在错误。

    不记得;数据库损坏!!!


    只要您无法更改数据库字符集并始终尝试删除并向损坏的表添加字段,就很难解决问题。 1.对于每个新测试,必须创建一个新数据库(提示:创建一个并复制x次)。 2.在原始字段中存储纯文本而非西里尔字符的字段;你看不到他们,但他们在那里。 3.将varchar(8191)和数据库PAGE_SIZE设置为8192.使用UTF8的实际最大VARCHAR长度为8191

    CREATE DATABASE语句:

    CREATE DATABASE localhost:mybase
      USER SYSDBA
      PASSWORD masterkey
      PAGE_SIZE 8192
      DEFAULT CHARACTER SET UTF8;
      SET NAMES ISO8859_1;
    
    CREATE TABLE scales (
      ID ...,      
      byteken VARCHAR(8191) COLLATE DE_DE,
      ....
    

    <强>排序规则

    没有默认排序规则。因此,您应为每个要用于排序(ORDER BY)或比较(UPPER)的字段定义排序规则:

    您还可以使用ORDER BY子句指定排序规则:

    ORDER BY LASTNAME COLLATE FR_CA, FIRSTNAME COLLATE FR_CA
    

    或WHERE子句:

    WHERE LASTNAME COLLATE FR_CA = :lastnametosearch
    

    <强>的Unicode

    Firebird 2.0。以上。现在有一个新的UTF8字符集可以正确处理UTF-8格式的Unicode字符串。已经实现了Unicode排序规则算法,现在您可以使用UPPER()和新的LOWER()函数,而无需指定排序规则。