Intersystems缓存 - 保持对象代码,以确保数据符合对象定义
我是新来使用intersytems缓存和面临的问题,我正在查询存储在缓存中的数据,暴露的类似乎不准确地代表数据基础系统。存储在全局变量中的数据几乎总是大于目标代码中定义的数据。Intersystems缓存 - 保持对象代码,以确保数据符合对象定义
因此,我经常遇到像下面这样的错误。
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的最大LEN定义的列,但是存储在系统中的数据是长6个字符。
如何主动监控和修复此类情况。
/*
我没有在高速缓存
*/
这不是完全清楚什么是“监测和修复”将意味着你的,但是:
多少控制你有在数据库端?使用数据类型的LogicalToODBC方法,高速缓存运行代码以实现从全局到ODBC的数据类型转换。如果将属性类型从%String更改为您自己的类AppropriatelyNamedString,则可以重写该方法以自动截断。如果这就是你想要做的。可以使用%Library.CompiledClass类以编程方式更改所有%String属性类型。
也可以在Cache内运行代码来查找属性超过(理论上)最大长度的记录。这显然需要全表扫描。甚至可以将该代码作为存储过程公开。
再一次,我不知道你到底在做什么,但这些都是一些选择。他们可能需要更深入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()
}
最简单的办法是增加MAXLEN参数,以6或更大的创建这些对象定义。 Caché只在保存时执行MAXLEN和TRUNCATE。在其他Caché代码中,这通常很好,但不幸的是,ODBC客户端往往期望更严格地执行此操作。另一种选择是写你的SQL SELECT一样LEFT(列名,5)...
我使用所有的集成服务包,例如最简单的方法是创建所有为nvarchar或char数据投射到正确长度的查询。通过这种方式,我的数据不会因截断而失败。 可选: 首先运行就像一个查询:从cachenamespace.tablename.mycolumnName SELECT MAX(DATALENGTH(mycolumnName))
新的查询:SELECT CAST(mycolumnname为varchar(6))作为mycolumnname, 转换(VARCHAR( 8000),memo_field)AS memo_field from cachenamespace.tablename.mycolumnName
您获取数据的痛苦会减轻但不会被消除。 如果您使用任何类型的oledb提供程序,或者如果您在SQL Server中使用OPENQUERY,则 中的强制转换必须发生在发送到Intersystems CACHE db的查询中,而不是在从内部OPENQUERY中检索数据的外部查询中。
一个合理但强力的解决方案。我已经进入了一个新的职位,因此不再处理这个问题,但是感谢您的时间和协助。就像所有其他选项一样,在哪里选择专业人士以及在哪里采取这些缺点。当我们这样做时,将所有内容定义为varchar(8000),这意味着我们将在内存分配和ETL性能方面失去很多效率。但在这种情况下,我认为它是可以的,因为选择是...高效,失败,或者完全没有效率,但完成工作。后者更具价值。 – 2017-09-22 16:08:27
@psr - 澄清修复:我的意思是确定大于sql表定义的数据并重新定义sql表。或者最低限度,开始向系统管理员提供指标,指明预期数据类型(类型和长度)中的数据百分比。 – 2012-01-17 18:08:56
如果您喜欢答案,则可以将其标记为已接受。 – psr 2012-01-19 23:43:17