예제 #1
0
		/// <summary>
		/// Loads the cache with all of the strings which will be needed by the ShortName
		/// property. For performance only.
		/// </summary>
		public static void PreLoadShortName(FdoCache cache)
		{
			// JohnT: there's seldom much point in doing this more than once. (That's bad enough!).
			// The main exception is Refresh, when we throw everything away and start over.
			// There might be other exceptions, such as after a major import.
			if (PreloadPerformedVirtualHandler.PreloadPerformed(cache))
				return;
#if DEBUG
			DateTime dt1 = DateTime.Now;
			int tc1 = System.Environment.TickCount;
#endif
			cache.LoadAllOfOneWsOfAMultiUnicode((int)LexEntry.LexEntryTags.kflidCitationForm,
				"LexEntry", cache.DefaultVernWs);
			// This seems to be needed because many lex entries (at least in some databases,
			// such as the Ron Moe one) don't have citation forms, and hence we go to some
			// related MoForm to get the short name for the lex entry.
			cache.LoadAllOfOneWsOfAMultiUnicode((int)
				MoForm.MoFormTags.kflidForm,
				"MoForm", cache.DefaultVernWs);
			// It seems to me (JohnT) that it should also be necessary to preload the
			// UnderlyingForm and Allomorphs properties, but testing with a large dictionary and
			// SQL profiler seems to confirm that it is not. Apparently something I don't know
			// about is preloading this information...perhaps part of pre-loading the sequence
			// of LexEntry objects?
			// Notice we're not preloading the analysis writing system, on the assumption that
			// that is rare. (JT: but, it isn't rare to CHECK and SEE whether there is an
			// analysis WS of the citation form, if we have that case at all and there is no
			// vernacular CF.  For now, I removed looking for the analysis CF from the ShortName
			// method, so it is OK not to preload it.

			// Preload the homograph numbers which will also be needed for the HeadWord, which
			// is used instead of ShortName when uniqueness is desired. Also include class info
			// to avoid later cache misses when loading the objects.
			IDbColSpec dcs = DbColSpecClass.Create();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctInt, 1,
				(int)CmObjectFields.kflidCmObject_Class, 0);
			dcs.Push((int)DbColType.koctObj, 1,
				(int)CmObjectFields.kflidCmObject_Owner, 0);
			dcs.Push((int)DbColType.koctInt, 1,
				(int)CmObjectFields.kflidCmObject_OwnFlid, 0);
			dcs.Push((int)DbColType.koctTimeStamp, 1, 0, 0);
			dcs.Push((int)DbColType.koctInt, 1,
				(int)LexEntry.LexEntryTags.kflidHomographNumber, 0);
			cache.LoadData("select Id, Class$, Owner$, OwnFlid$, UpdStmp, HomographNumber from LexEntry_", dcs, 0);

			// Preload the LexemeForm for each LexEntry.
			dcs.Clear();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctObjOwn, 1,
				(int)LexEntry.LexEntryTags.kflidLexemeForm, 0);
			cache.LoadData("select Src, Dst from LexEntry_LexemeForm", dcs, 0);

			// Preload the allomorphs for each LexEntry.  This is needed to obtain the morph
			// types, which are properties of the allomorphs.
			dcs.Clear();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctObjVecOwn, 1,
				(int)LexEntry.LexEntryTags.kflidAlternateForms, 0);
			cache.LoadData("select Src, Dst from LexEntry_AlternateForms order by Src,Ord", dcs, 0);

			// Preload the morphtype for each allomorph (MoForm).
			dcs.Clear();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctObj, 1, (int)MoForm.MoFormTags.kflidMorphType,
				0);
			cache.LoadData("select Id,MorphType from MoForm", dcs, 0);

			// Preload the information for MoMorphTypes.
			dcs.Clear();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctUnicode, 1,
				(int)MoMorphType.MoMorphTypeTags.kflidPostfix, 0);
			dcs.Push((int)DbColType.koctUnicode, 1,
				(int)MoMorphType.MoMorphTypeTags.kflidPrefix, 0);
			dcs.Push((int)DbColType.koctInt, 1,
				(int)MoMorphType.MoMorphTypeTags.kflidSecondaryOrder, 0);
			cache.LoadData("select Id,Postfix,Prefix,SecondaryOrder from MoMorphType", dcs, 0);

			PreloadPerformedVirtualHandler.SetPreloadPerformed(cache);
#if DEBUG
			int tc2 = System.Environment.TickCount;
			TimeSpan ts1 = DateTime.Now - dt1;
			string s = "Preloading for LexEntry ShortNames took " + (tc2 - tc1) + " ticks," +
				" or " + ts1.Minutes + ":" + ts1.Seconds + "." +
				ts1.Milliseconds.ToString("d3") + " min:sec.";
			Debug.WriteLine(s);
#endif

			Marshal.ReleaseComObject(dcs); //jdh added dec 1, 2004
		}
예제 #2
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Loads the cache with all of the data needed to display a hierarchical list, plus
		/// strings which will be needed by the ShortName property (which may include
		/// abbreviation). For performance only.
		/// Using this preload plus keeping the tree view from inadvertently loading extra data
		/// reduced the number of queries to start LexText on the Semantic Domain list from
		/// around 19,000 queries to 200.
		/// </summary>
		/// <param name="cache">The cache.</param>
		/// <param name="hvoList">The hvo list.</param>
		/// <returns></returns>
		/// ------------------------------------------------------------------------------------
		public static Set<int> PreLoadList(FdoCache cache, int hvoList)
		{
			DateTime dt1 = DateTime.Now;
			int tc1 = System.Environment.TickCount;

			int flidPssl = (int)CellarModuleDefns.kflidCmPossibilityList_Possibilities;
			int flidPss = (int)CellarModuleDefns.kflidCmPossibility_SubPossibilities;
			// Note: This query will not run from code with nocount off.
			string squery =
				" declare @fIsNocountOn int" +
				" set @fIsNocountOn = @@options & 512" +
				" if @fIsNocountOn = 0 set nocount on" +
				" select goi.Owner$, goi.OwnFlid$, goi.id, goi.Class$, goi.UpdStmp, cn.Txt, ca.Txt " +
				" from dbo.fnGetOwnedIds(" + hvoList + ", " + flidPssl + ", " + flidPss + ") goi" +
				" left outer join CmPossibility_Name cn on cn.obj = goi.id and cn.ws = " + cache.DefaultAnalWs +
				" left outer join CmPossibility_Abbreviation ca on ca.obj = goi.id and ca.ws = " + cache.DefaultAnalWs +
				" order by goi.Owner$, goi.OwnOrd$ " +
				" if @fIsNocountOn = 0 set nocount off";
			IDbColSpec dcs = DbColSpecClass.Create();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctFlid, 1, 0, 0);	// flid for vector
			dcs.Push((int)DbColType.koctObjVecOwn, 1, 0, 0);
			dcs.Push((int)DbColType.koctInt, 3, (int)CmObjectFields.kflidCmObject_Class, 0);
			dcs.Push((int)DbColType.koctTimeStamp, 3, 0, 0);
			dcs.Push((int)DbColType.koctMltAlt, 3,
				(int)CmPossibility.CmPossibilityTags.kflidName, cache.DefaultAnalWs);
			dcs.Push((int)DbColType.koctMltAlt, 3,
				(int)CmPossibility.CmPossibilityTags.kflidAbbreviation, cache.DefaultAnalWs);
			cache.LoadData(squery, dcs, 0);

			// Get a list of all of the items that we've already cached.
			ISilDataAccess sda = cache.MainCacheAccessor;
			int beginSize = 500;
			Set<int> alHvos = new Set<int>(beginSize);
			CmPossibility.GetItems(hvoList, flidPssl, alHvos, sda, true);

			// only do this if the cellar timing switch is info or verbose
			if (RuntimeSwitches.CellarTimingSwitch.TraceInfo)
			{
			int tc2 = System.Environment.TickCount;
			TimeSpan ts1 = DateTime.Now - dt1;
			string s = "PreLoadList for CmPossibility took " + (tc2 - tc1) + " ticks," +
				" or " + ts1.Minutes + ":" + ts1.Seconds + "." +
				ts1.Milliseconds.ToString("d3") + " min:sec.";
				Debug.WriteLine(s, RuntimeSwitches.CellarTimingSwitch.DisplayName);
			}

			return alHvos;
		}
예제 #3
0
		/// <summary>
		/// Loads the cache with all of the strings which will be needed by the ShortName
		/// property. For performance only.
		/// </summary>
		public static void PreLoadShortName(FdoCache cache, int ws)
		{
#if DEBUG
			DateTime dt1 = DateTime.Now;
			int tc1 = System.Environment.TickCount;
#endif
			cache.LoadAllOfOneWsOfAMultiUnicode((int)WfiWordform.WfiWordformTags.kflidForm,
				"WfiWordform", ws);

			// Include other basic parts of WfiWordform
			// to avoid later cache misses when loading the objects.
			IDbColSpec dcs = DbColSpecClass.Create();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID
			dcs.Push((int)DbColType.koctInt, 1,
				(int)CmObjectFields.kflidCmObject_Class, 0);
			dcs.Push((int)DbColType.koctObj, 1,
				(int)CmObjectFields.kflidCmObject_Owner, 0);
			dcs.Push((int)DbColType.koctInt, 1,
				(int)CmObjectFields.kflidCmObject_OwnFlid, 0);
			dcs.Push((int)DbColType.koctTimeStamp, 1, 0, 0);
			cache.LoadData("select Id, Class$, Owner$, OwnFlid$, UpdStmp from CmObject where class$ = "
				+ WfiWordform.kClassId, dcs, 0);

#if DEBUG
			int tc2 = System.Environment.TickCount;
			TimeSpan ts1 = DateTime.Now - dt1;
			string s = "Preloading for WfiWordform ShortNames took " + (tc2 - tc1) + " ticks," +
				" or " + ts1.Minutes + ":" + ts1.Seconds + "." +
				ts1.Milliseconds.ToString("d3") + " min:sec.";
			Debug.WriteLine(s);
#endif

			Marshal.ReleaseComObject(dcs);
		}
예제 #4
0
		/// <summary>
		/// Load the information we need to display a paragraph of free (back) translations: for each paragraph
		/// load its segments, for each segment load the free translation. We assume the segments
		/// property of each paragraph already exists, and want the BeginOffset, EndOffset, BeginObject, and Free Translation
		/// properties of each segment, and the Comment of the FT.
		/// Also ensures all the segments are real and have an FT annotation.
		/// </summary>
		/// <param name="paragraphs"></param>
		/// <param name="cache"></param>
		/// <param name="ws"></param>
		public static void LoadSegmentFreeTranslations(int[] paragraphs, FdoCache cache, int ws)
		{
			int kflidSegments = SegmentsFlid(cache);
			List<int> segments = new List<int>();
			foreach (int hvoPara in paragraphs)
			{
				int[] segs = cache.GetVectorProperty(hvoPara, kflidSegments, true);
				int iseg = 0;
				foreach (int hvoSeg in segs)
				{
					int hvoRealSeg = hvoSeg;
					if (cache.IsDummyObject(hvoSeg))
						hvoRealSeg = CmBaseAnnotation.ConvertBaseAnnotationToReal(cache, hvoSeg).Hvo;
					segments.Add(hvoRealSeg);
					segs[iseg++] = hvoRealSeg;
				}
				// Update the list.
				cache.VwCacheDaAccessor.CacheVecProp(hvoPara, kflidSegments, segs, segs.Length);
			}

			if (segments.Count == 0)
				return; // somehow we can have none, and then the query fails.

			int hvoFt = cache.GetIdFromGuid(LangProject.kguidAnnFreeTranslation);
			string ids = JoinIds(segments.ToArray(), ",");
			int kflidFT = SegmentFreeTranslationFlid(cache);

			if (cache.DatabaseAccessor != null)
			{
				string sql =
					@"select seg.id, seg.BeginObject, seg.BeginOffset, seg.EndOffset, ft.id, ft.class$, ft.UpdStmp, ftc.Txt, ftc.Fmt from CmBaseAnnotation seg
					join CmIndirectAnnotation_AppliesTo ftseg on ftseg.Dst = seg.id
					join CmIndirectAnnotation_ ft on ft.id = ftseg.Src and ft.AnnotationType = " +
					hvoFt + @"
					left outer join CmAnnotation_Comment ftc on ftc.Obj = ft.id and ftc.ws = " + ws +
					@"
					where seg.id in (" + ids + ")";
				IDbColSpec dcs = DbColSpecClass.Create();
				dcs.Push((int) DbColType.koctBaseId, 0, 0, 0); // ID (of segment)
				dcs.Push((int) DbColType.koctObj, 1, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject, 0);
				dcs.Push((int) DbColType.koctInt, 1, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginOffset, 0);
				dcs.Push((int) DbColType.koctInt, 1, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidEndOffset, 0);
				dcs.Push((int) DbColType.koctObj, 1, kflidFT, 0); // Free translation indirect annotation
				dcs.Push((int) DbColType.koctInt, 5, (int) CmObjectFields.kflidCmObject_Class, 0); // class of FT annotation
				dcs.Push((int) DbColType.koctTimeStamp, 5, 0, 0); // timestamp of FT annotation
				dcs.Push((int)DbColType.koctMlsAlt, 5, (int)CmAnnotation.CmAnnotationTags.kflidComment, ws);
				dcs.Push((int)DbColType.koctFmt, 5, (int)CmAnnotation.CmAnnotationTags.kflidComment, ws);
				cache.LoadData(sql, dcs, 0);
			}

			// Make sure each segment has a free translation.
			foreach (int hvoSeg in segments)
			{
				int hvoFT = cache.GetObjProperty(hvoSeg, kflidFT);
				if (hvoFT == 0)
				{
					ICmIndirectAnnotation ann = CmIndirectAnnotation.CreateUnownedIndirectAnnotation(cache);
					ann.AppliesToRS.Append(hvoSeg);
					ann.AnnotationTypeRAHvo = hvoFt;
					cache.VwCacheDaAccessor.CacheObjProp(hvoSeg, kflidFT, ann.Hvo);
				}
			}
		}
예제 #5
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Load all fields of all objects of this type that have a owning flid contained in
		/// flids.
		/// </summary>
		/// <param name="fdoClassType">The class of the object</param>
		/// <param name="cache">The FDO cache.</param>
		/// <param name="flids">The owning fields of the owner of the objects we want to load
		/// data for. Might be <c>null</c> for ownerless objects</param>
		/// <param name="parentViewName">The view name of the parent class.</param>
		/// ------------------------------------------------------------------------------------
		public static void LoadDataForFlids(Type fdoClassType, FdoCache cache, int[] flids,
			string parentViewName)
		{
			Debug.Assert(flids == null || flids.Length != 0);

			string sViewName = (string)GetStaticField(fdoClassType, "FullViewName");
			Debug.Assert(sViewName != null);

			StringBuilder sQry = new StringBuilder("select cmo.* from " + sViewName + " cmo");
			if (flids != null)
			{
				sQry.Append(" join " +
					parentViewName + " x on cmo.owner$ = x.id and x.ownflid$ in (");
				foreach (int flid in flids)
				{
					sQry.Append(flid);
					sQry.Append(",");
				}
				// replace last , with )
				sQry[sQry.Length - 1] = ')';
			}

			IDbColSpec dcs = DbColSpecClass.Create();
			try
			{
				AddBasicFieldsToColumnSpec(fdoClassType, dcs, cache);

				cache.LoadData(sQry.ToString(), dcs, 0);
			}
			finally
			{
				Marshal.ReleaseComObject(dcs);
			}
		}
예제 #6
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// given a type and an array of hvos of objects of that type, cache the vector properties of these objects
		/// </summary>
		/// <param name="cache">FdoCache</param>
		/// <param name="csharpType"></param>
		/// <param name="hvos">an array of hvos of homogeneous objects, which all must be of
		/// type csharpType (not checked).
		/// If null, just load all of the objects of this type(much faster for long lists)</param>
		/// ------------------------------------------------------------------------------------
		public static void LoadVectorData(FdoCache cache, Type csharpType, int[] hvos)
		{
			Debug.Assert(csharpType != null);
			//NO: hvos=null now means we should load them all (*much faster*): Debug.Assert(hvos != null);
			if (hvos != null)
			{
				Debug.Assert(hvos.Length>0);
			}

			// note: the "FlattenHierarchy" is needed here because the class we are giving it is "XXX" one,
			//	but this property is on its superclass,"BaseXXXX"
			System.Reflection.FieldInfo fi = csharpType.GetField("VectorFlids",
				System.Reflection.BindingFlags.FlattenHierarchy |
				System.Reflection.BindingFlags.NonPublic | //these are marked "internal"
				System.Reflection.BindingFlags.Static);
			Debug.Assert(fi != null);
			int[] flids = (int[]) fi.GetValue(null);

			fi = csharpType.GetField("VectorViewNames",
				System.Reflection.BindingFlags.FlattenHierarchy |
				System.Reflection.BindingFlags.NonPublic | //these are marked "internal"
				System.Reflection.BindingFlags.Static);
			Debug.Assert(fi != null);
			string[] views = (string[]) fi.GetValue(null);

			fi = csharpType.GetField("VectorIsSequence",
				System.Reflection.BindingFlags.FlattenHierarchy |
				System.Reflection.BindingFlags.NonPublic | //these are marked "internal"
				System.Reflection.BindingFlags.Static);
			Debug.Assert(fi != null);
			bool[] sequenceBools = (bool[]) fi.GetValue(null);

			for(int i=0; i < flids.Length; i++)
			{
				if(flids[i] !=0) // 0 is an artifact of the xslt generator
				{
					IDbColSpec dcs = DbColSpecClass.Create();
					//dcs.Clear();
					dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);
					dcs.Push((int)DbColType.koctObjVec, 1, (int)flids[i], 0);

					//Enhance (JH): this would be much faster using the stringBuilder, for large lists

					// BUILD THE QUERY FOR THIS VECTOR PROPERTY
					string sQry = "select * from " + views[i] + " ";

					if(hvos != null)
					{
						sQry += "where src in ("; // don't just add to original sQry, that is used in else branch.
						int iNextGroup = 0;
						while (iNextGroup < hvos.Length)
						{
							string sQry2 = sQry + CmObject.MakePartialIdList(ref iNextGroup, hvos) + ") order by Src";
							// See John Hatton's comment below about ordering, which was made before this section was added.
							if(sequenceBools[i])
								sQry2 += ", ord";
							cache.LoadData(sQry2, dcs, 0);
						}
					}
					else
					{
						/*	(John Hatton) I removed this ordering (12 Nov 2002) because it can cause the underlying cache to miss some values.
							For example, with "order by ord", we get the following:
								Src         Dst         Ord
							----------- ----------- -----------
							11656       9183        0
							11657       9183        0
							11658       9183        0
							11659       9183        0
							11659       1596        1
							11658       2269        1
							11657       4565        1
							11656       4572        1

							Here, the objects 11656, 11657, and 11658 were getting the element 918 (i.e. the ord 0 elements),
							but were not getting the ord 1 elements.  Only object 11659 was getting both of its elements correctly,
							because there was no break.  In other words, it is as if the underlying cache requires that these things
							be sorted by Src.

							if(sequenceBools[i])
								sQry += " order by ord";
						*/

						sQry += "order by Src";
						if(sequenceBools[i])
							sQry += ", ord";

						cache.LoadData(sQry, dcs, 0);
					}
					System.Runtime.InteropServices.Marshal.ReleaseComObject(dcs);
				}
			}
		}
예제 #7
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// load into the cache the IDs of the objects which are owned in atomic properties by these objects
		/// </summary>
		/// <param name="cache">FdoCache</param>
		/// <param name="csharpType">Type of the objects to load</param>
		/// <param name="hvos">an array of hvos of homogeneous objects, which
		/// all must be of type csharpType (not checked).
		/// Set to null if you just want to load all of the objects of this type.</param>
		/// <param name="classId">Required if hvos is null</param>
		/// ------------------------------------------------------------------------------------
		public static void LoadOwningAtomicData(FdoCache cache,Type csharpType, int[] hvos, int classId)
		{
			Debug.Assert(csharpType != null);
			//hvos == null is now allowed  Debug.Assert(hvos != null);
			if(hvos != null)
			{
				Debug.Assert(hvos.Length>0);
			}
			if (cache.VwOleDbDaAccessor == null)
				return; // some sort of memory cache, assume preloaded.

			string sSelectClause = "obj.Id, ";
			string sFromClause="CmObject as obj ";
			string sWhereClause="";

			// begin the column spec.  Later, we will push a new item for each field.
			IDbColSpec dcs = DbColSpecClass.Create();
			dcs.Push((int)DbColType.koctBaseId, 0, 0, 0);	// ID

			// begin the where clause, which will be added to later by BuildOwningAtomicLoadSpec()
			//sWhereClause = "obj.Id in (";
			if(hvos == null)
			{
				Debug.Assert(classId > -1, "You must provide a classId to if you are not specifying the hvos.");
				sWhereClause = " where obj.class$ = " + classId.ToString();
			}
			else
			{
				sWhereClause = " where obj.Id in (";
				for(int i =hvos.Length -1; i>0; i--)
				{
					if (hvos[i] > 0)
						sWhereClause += hvos[i].ToString() + ",";
				}
				if (hvos[0] > 0)
					sWhereClause += hvos[0].ToString();
				sWhereClause += ") ";	// no "," after this last one
			}

			BuildOwningAtomicLoadSpec(csharpType, dcs, ref sSelectClause, ref sFromClause);

			//put all of these pieces together into a select statement
			//string sQuery ="select " +sSelectClause+" From " + sFromClause + "  where " + sWhereClause;
			string sQuery ="select " +sSelectClause+" from " + sFromClause + sWhereClause;
			cache.LoadData(sQuery, dcs, 0);
			System.Runtime.InteropServices.Marshal.ReleaseComObject(dcs);
		}
예제 #8
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// load the data which is found in the tables representing the class and its superclasses
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="fdoClassType">the CSharp type corresponding to the array of hvos</param>
		/// <param name="hvos">If null, just load all of the objects of this type(much faster for long lists)</param>
		/// ------------------------------------------------------------------------------------
		private static void LoadBasicData(FdoCache cache, Type fdoClassType, int[] hvos)
		{
			if (hvos != null && hvos.Length == 0 || cache.VwOleDbDaAccessor == null)
				return; // nothing needs to be loaded (and our query would fail with empty list), or non-database cache.
			Debug.Assert(fdoClassType != null);

			// populate column spec
			IDbColSpec dcs = DbColSpecClass.Create();
			AddBasicFieldsToColumnSpec(fdoClassType, dcs, cache);

			// Build select query
			string sViewName = (string)GetStaticField(fdoClassType, "FullViewName");
			Debug.Assert(sViewName != null);

			// We want to use explicit field names here because custom fields don't get added to dcs.
			StringBuilder sQryBldr = new StringBuilder("select id, guid$, class$, owner$, ownflid$, ownord$, updstmp, upddttm");
			string fields = "";
			if (s_colNames.ContainsKey(fdoClassType))
			{
				fields = s_colNames[fdoClassType];
			}
			else
			{
				IFwMetaDataCache mdc = cache.MetaDataCacheAccessor;
				if (mdc != null)
				{
					// Should never be null, except when testing with a mock cache.
					StringBuilder fieldsBldr = new StringBuilder("");
					int cspec;
					dcs.Size(out cspec);
					for (int i = 8; i < cspec; i++)
					{
						int tag;
						dcs.GetTag(i, out tag);
						string fieldName = mdc.GetFieldName((uint)tag);
						int oct;
						dcs.GetDbColType(i, out oct);
						fieldsBldr.AppendFormat(", [{0}", fieldName);
						if (oct == (int)DbColType.koctFmt)
							fieldsBldr.Append("_Fmt");
						fieldsBldr.Append("]");
					}
					// NB: Don't cache the result if no mdc, as later tests may have one!
					fields = fieldsBldr.ToString();
					s_colNames[fdoClassType] = fields;
				}
			}
			if (fields.Length > 0)
				sQryBldr.Append(fields);
			sQryBldr.AppendFormat(" FROM {0} ", sViewName);

			if (hvos != null)
			{
				sQryBldr.Append(" where id in (");
				int iNextGroup = 0;
				while (iNextGroup < hvos.Length)
				{
					string sQry2 = String.Format("{0}{1})", sQryBldr.ToString(), CmObject.MakePartialIdList(ref iNextGroup, hvos));
					cache.LoadData(sQry2, dcs, 0);
				}
			}
			else
			{
				cache.LoadData(sQryBldr.ToString(), dcs, 0);
			}
			System.Runtime.InteropServices.Marshal.ReleaseComObject(dcs);
		}