2011-12-20 40 views
1

我是新來使用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個字符。

如何主動監控和修復此類情況。

/*

我沒有在高速緩存

*/

+0

@psr - 澄清修復:我的意思是確定大於sql表定義的數據並重新定義sql表。或者最低限度,開始向系統管理員提供指標,指明預期數據類型(類型和長度)中的數據百分比。 – 2012-01-17 18:08:56

+0

如果您喜歡答案,則可以將其標記爲已接受。 – psr 2012-01-19 23:43:17

回答

3

這不是完全清楚什麼是「監測和修復」將意味着你的,但是:

多少控制你有在數據庫端?使用數據類型的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() 
} 
0

最簡單的辦法是增加MAXLEN參數,以6或更大的創建這些對象定義。 Caché只在保存時執行MAXLEN和TRUNCATE。在其他Caché代碼中,這通常很好,但不幸的是,ODBC客戶端往往期望更嚴格地執行此操作。另一種選擇是寫你的SQL SELECT一樣LEFT(列名,5)...

0

我使用所有的集成服務包,例如最簡單的方法是創建所有爲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中檢索數據的外部查詢中。

+0

一個合理但強力的解決方案。我已經進入了一個新的職位,因此不再處理這個問題,但是感謝您的時間和協助。就像所有其他選項一樣,在哪裏選擇專業人士以及在哪裏採取這些缺點。當我們這樣做時,將所有內容定義爲varchar(8000),這意味着我們將在內存分配和ETL性能方面失去很多效率。但在這種情況下,我認爲它是可以的,因爲選擇是...高效,失敗,或者完全沒有效率,但完成工作。後者更具價值。 – 2017-09-22 16:08:27