1

我是使用系统间缓存的新手,并面临一个问题,即我正在查询存储在缓存中的数据,这些数据由似乎不能准确表示底层系统中的数据的类公开。存储在全局变量中的数据几乎总是大于目标代码中定义的数据。

因此,我经常遇到如下错误。

Msg 7347, Level 16, State 1, Line 2
OLE DB provider 'MSDASQL' for linked server 'cache' returned data that does not match expected data length for column '[cache]..[namespace].[tablename].columname'. The (maximum) expected data length is 5, while the returned data length is 6.

有没有人有实施某种类型的质量过程以确保对象定义(sql 映射)被维护得足够远,以至于它们可以容纳在全局变量中持久保存的数据的经验?

Property columname As %String(MAXLEN = 5, TRUNCATE = 1) [ Required, SqlColumnNumber = 2, SqlFieldName = columname ];

在此特定示例中,系统定义了最大长度为 5 的列,但是存储在系统中的数据长度为 6 个字符。

如何主动监控和修复此类情况。

/*

我没有在缓存中创建这些对象定义

*/

4

3 回答 3

3

目前尚不完全清楚“监控和维修”对您意味着什么,但是:

您对数据库端有多少控制权?Cache 在使用数据类型类的 LogicalToODBC 方法从全局转换为 ODBC 时运行数据类型的代码。如果您将属性类型从 %String 更改为您自己的类 AppropriatelyNamedString,那么您可以覆盖该方法以自动截断。如果那是你想做的。可以使用 %Library.CompiledClass 类以编程方式更改所有 %String 属性类型。

也可以在 Cache 中运行代码来查找属性超过(有些理论上的)最大长度的记录。这显然需要全表扫描。甚至可以将该代码公开为存储过程。

同样,我不知道您到底想做什么,但这些是一些选择。他们可能确实需要比您更喜欢的缓存方面。

至于首先防止坏数据,没有通用的答案。缓存允许程序员直接写入全局变量,绕过任何对象或表定义。如果发生这种情况,则必须直接修复这样做的代码。

编辑:这是可能用于检测不良数据的代码。如果您正在做一些有趣的事情,它可能不起作用,但它对我有用。这有点难看,因为我不想把它分解成方法或标签。这意味着从命令提示符运行,因此可能必须根据您的目的对其进行修改。

{
    S ClassQuery=##CLASS(%ResultSet).%New("%Dictionary.ClassDefinition:SubclassOf")
    I 'ClassQuery.Execute("%Library.Persistent")  b  q
    While ClassQuery.Next(.sc) {
    If $$$ISERR(sc) b  Quit
        S ClassName=ClassQuery.Data("Name")
        I $E(ClassName)="%"   continue
        S OneClassQuery=##CLASS(%ResultSet).%New(ClassName_":Extent")
        I '$IsObject(OneClassQuery) continue  //may not exist
        try {
        I 'OneClassQuery.Execute()  D OneClassQuery.Close() continue
        }
        catch
        {

            D OneClassQuery.Close()
            continue
        }
        S PropertyQuery=##CLASS(%ResultSet).%New("%Dictionary.PropertyDefinition:Summary")
        K Properties
        s sc=PropertyQuery.Execute(ClassName)  I 'sc D PropertyQuery.Close()  continue
        While PropertyQuery.Next()
        {
            s PropertyName=$G(PropertyQuery.Data("Name"))
            S PropertyDefinition=""
            S PropertyDefinition=##CLASS(%Dictionary.PropertyDefinition).%OpenId(ClassName_"||"_PropertyName)
            I '$IsObject(PropertyDefinition)  continue
            I PropertyDefinition.Private  continue
            I PropertyDefinition.SqlFieldName=""    
            {
                S Properties(PropertyName)=PropertyName
            }
            else
            {
                I PropertyName'="" S Properties(PropertyDefinition.SqlFieldName)=PropertyName
            }
        }
        D PropertyQuery.Close()

        I '$D(Properties) continue

        While OneClassQuery.Next(.sc2)  {
            B:'sc2
            S ID=OneClassQuery.Data("ID")
            Set OneRowQuery=##class(%ResultSet).%New("%DynamicQuery:SQL")
            S sc=OneRowQuery.Prepare("Select * FROM "_ClassName_" WHERE ID=?") continue:'sc
            S sc=OneRowQuery.Execute(ID) continue:'sc
            I 'OneRowQuery.Next() D OneRowQuery.Close() continue
            S PropertyName=""
            F  S PropertyName=$O(Properties(PropertyName))  Q:PropertyName=""  d
            . S PropertyValue=$G(OneRowQuery.Data(PropertyName))
            . I PropertyValue'="" D
            .. S PropertyIsValid=$ZOBJClassMETHOD(ClassName,Properties(PropertyName)_"IsValid",PropertyValue)
            .. I 'PropertyIsValid W !,ClassName,":",ID,":",PropertyName," has invalid value of "_PropertyValue
            .. //I PropertyIsValid W !,ClassName,":",ID,":",PropertyName," has VALID value of "_PropertyValue
            D OneRowQuery.Close()
        }
        D OneClassQuery.Close()
    }   
    D ClassQuery.Close()
}
于 2012-01-16T18:49:48.670 回答
0

最简单的解决方案是将 MAXLEN 参数增加到 6 或更大。Caché 仅在保存时强制执行 MAXLEN 和 TRUNCATE。在其他 Caché 代码中,这通常很好,但不幸的是,ODBC 客户端往往希望这会得到更严格的执行。另一种选择是编写您的 SQL,例如 SELECT LEFT(columnname, 5)...

于 2011-12-20T01:55:46.990 回答
0

例如,我用于所有集成服务包的最简单的解决方案是创建一个查询,将所有 nvarchar 或 char 数据转换为正确的长度。这样,我的数据永远不会因截断而失败。可选:首先运行如下查询:SELECT Max(datalength(mycolumnName)) from cachenamespace.tablename.mycolumnName

您的新查询: SELECT cast(mycolumnname as varchar(6) ) as mycolumnname, convert(varchar(8000), memo_field) AS memo_field from cachenamespace.tablename.mycolumnName

您获取数据的痛苦将减轻但不会消除。如果您使用任何类型的 oledb 提供程序,或者如果您在 SQL Server 中使用 OPENQUERY,则强制转换必须发生在发送到 Intersystems CACHE db 的查询中,而不是从内部 OPENQUERY 检索数据的外部查询中。

于 2017-09-21T15:03:13.570 回答