Intersystems Cache - поддержка объектного кода для обеспечения соответствия данных определению объекта - PullRequest
1 голос
/ 20 декабря 2011

Я новичок в использовании межсистемного кеша и сталкиваюсь с проблемой, когда я запрашиваю данные, хранящиеся в кеше, выставленные классами, которые, похоже, не точно представляют данные в базовой системе. Данные, хранящиеся в глобальных переменных, почти всегда больше, чем те, которые определены в объектном коде.

В связи с этим я очень часто получаю ошибки, подобные приведенной ниже.

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 символов.

Как я могу активно отслеживать и исправлять такие ситуации.

/ ** * 1013

Я не создал эти определения объектов в кеше

* /

Ответы [ 3 ]

3 голосов
/ 16 января 2012

Не совсем понятно, что для вас будет означать «мониторинг и ремонт», но:

Насколько вы контролируете базу данных? Кэш выполняет код для типа данных при преобразовании из глобального в ODBC с использованием метода LogicalToODBC класса данных. Если вы измените типы свойств с% String на свой собственный класс, AppappatelyNamedString, вы можете переопределить этот метод для автоматического усечения. Если это то, что вы хотите сделать. Можно изменить все типы свойств% String программно, используя класс% Library.CompiledClass.

Также возможно запустить код в 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()
}
0 голосов
/ 21 сентября 2017

Простейшее решение, которое я использую, например, для всех пакетов служб Integration Services, - это создание запроса, который приводит все данные nvarchar или char к правильной длине. Таким образом, мои данные никогда не пересекаются. Необязательный: Сначала выполните запрос, например: SELECT Max (длина данных (mycolumnName)) из cachenamespace.tablename.mycolumnName

Ваш новый запрос: SELECT cast (mycolumnname as varchar (6)) как mycolumnname, convert (varchar (8000), memo_field) AS memo_field от cachenamespace.tablename.mycolumnName

Ваша боль при получении данных будет уменьшена, но не устранена. Если вы используете какой-либо тип поставщика oledb, или если вы используете OPENQUERY в SQL Server, преобразования должны происходить в запросе, отправляемом в Intersystems CACHE db, а не во внешний запрос, который извлекает данные из внутреннего OPENQUERY.

0 голосов
/ 20 декабря 2011

Самое простое решение - увеличить параметр MAXLEN до 6 или больше.При сохранении Caché применяет только MAXLEN и TRUNCATE.В другом коде Caché это обычно нормально, но, к сожалению, клиенты ODBC ожидают, что это будет выполняться более строго.Другой вариант - написать свой SQL как SELECT LEFT (columnname, 5) ...

...