<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://communities.bentley.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>[CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas</link><description>I&amp;#39;m looking at elements that have XAttributes on them. I can create a ECQuery to find instances on an element. When I look at what is found, it is not uncommon to find multiple Classes on an element. For example: 
 
 [DgnElementSchema:LineElement] [DgnCustomItemTypes_SRSFeature</description><dc:language>en-US</dc:language><generator>Telligent Community 12</generator><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/553719?ContentTypeID=1</link><pubDate>Mon, 11 Nov 2019 02:27:48 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:ae3dc792-533e-4e8f-a30e-22924d6b8839</guid><dc:creator>Yongan.Fu</dc:creator><description>&lt;p&gt;Hi Bruce,&lt;/p&gt;
&lt;p&gt;If you only want to find a specific [&lt;span&gt;ECShema:&lt;/span&gt;ECClass] on an element, I think it doesn&amp;#39;t need to use WhereCriterion. Below is an example which can get [BaseElementSchema:MstnVolume] on an element.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void getVolumeByEC(WCharCP unparsed)
{
	ElementId id = wcstol(unparsed, NULL, 10);
	ElementHandle eh(id, ACTIVEMODEL);
	if (!eh.IsValid())
	{
		mdlDialog_dmsgsPrint(L&amp;quot;invalid element handle&amp;quot;);
		return;
	}
	DgnFileP dgnFile = ISessionMgr::GetActiveDgnFile();
	SchemaInfo schemaInfo(ECN::SchemaKey(L&amp;quot;BaseElementSchema&amp;quot;, 1, 0), *dgnFile);
	DgnECManagerR ecMan = DgnECManager::GetManager();
	ECN::ECSchemaPtr pSchema = ecMan.LocateSchemaInDgnFile(schemaInfo, ECN::SchemaMatchType::SCHEMAMATCHTYPE_LatestCompatible);
	if (pSchema.IsNull())
	{
		mdlDialog_dmsgsPrint(L&amp;quot;Can&amp;#39;t find BaseElementSchema schema&amp;quot;);
		return;
	}
	ECN::ECClassCP pVolClass = pSchema-&amp;gt;GetClassCP(L&amp;quot;MstnVolume&amp;quot;);
	DgnElementECInstancePtr pInstance = ecMan.FindInstanceOnElement(eh, *pVolClass, true); //polymorphic=true is important
	if (pInstance.IsNull())
	{
		mdlDialog_dmsgsPrint(L&amp;quot;pInstance is null&amp;quot;);
		return;
	}
	WString strVal;
	pInstance-&amp;gt;GetValueAsString(strVal, L&amp;quot;SurfaceArea&amp;quot;, false, 1);
	mdlDialog_dmsgsPrint(strVal.GetWCharCP());
	pInstance-&amp;gt;GetValueAsString(strVal, L&amp;quot;Volume&amp;quot;, false, 1);
	mdlDialog_dmsgsPrint(strVal.GetWCharCP());
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;An example of using WhereCriterion is as below:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="ruby"&gt;WhereCriterionPtr wh = WhereCriterion::CreatePropertyComparison(propertyName, WhereCriterion::EQ, propertyValue);
myQuery-&amp;gt;SetWhereCriterion (*wh);
myResult = DgnECManager::GetManager().FindInstances(*scope, *myQuery);&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/551417?ContentTypeID=1</link><pubDate>Tue, 29 Oct 2019 09:37:10 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:c1f17c05-3704-4e07-9228-274800ecd55f</guid><dc:creator>Jan Šlegr</dc:creator><description>&lt;p&gt;Hi John,&lt;/p&gt;
&lt;p&gt;I guess it goes a bit beyond scope of this discussion, but anyway... ;-)&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]I don&amp;#39;t understand the concepts or design that went into the EC query language.&amp;nbsp; I find it hard to use and suspect that I am not alone.[/quote]
&lt;p&gt;That&amp;#39;s probably true. But I guess it wise to split EC query &amp;quot;language&amp;quot; and how it&amp;#39;s implemented in API.&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]Here are some other paths that Bentley Systems might have considered...[/quote]
&lt;p&gt;That&amp;#39;s a bit unfair in my opinion, because you want to evaluate technology invented (I guess) more than 10 years ago with pretty complex structure of features and priorities from today perspective. The then decisions can be decided not best easily in such position.&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]If data are stored as XML fragments&amp;nbsp; and schemas are XML, then why not use the XML query language &lt;a title="W3Schools.Com: XQuery" href="https://www.w3schools.com/xml/xquery_intro.asp" rel="noopener noreferrer" target="_blank"&gt;XQuery&lt;/a&gt;?[/quote]
&lt;p&gt;XQuery focuses unstructured data and it&amp;#39;s not context-sensitive tool. Which does not mean XQuery (and XPath) is not seriously powerful tool, but ECQuery is designed to work in defined EC Schema context, which I guess can be hardly implemented into XQuery.&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]Why not make them exactly like SQL by incorporating a &lt;a title="Wikipedia: Domain Specific Language" href="https://en.wikipedia.org/wiki/Domain-specific_language" rel="noopener noreferrer" target="_blank"&gt;domain specific language&lt;/a&gt; (DSL) compiler?[/quote]
&lt;p&gt;&lt;a href="https://imodeljs.github.io/iModelJs-docs-output/learning/ecsql/" rel="noopener noreferrer" target="_blank"&gt;ECSQL&lt;/a&gt; is available already in iModelJS API. It&amp;#39;s all about steady development of the whole technology and implementing new features and tools, where some are not backward compatible (e.g. &lt;a href="https://imodeljs.github.io/iModelJs-docs-output/bis/ec/differences-between-ec2-and-ec3/" rel="noopener noreferrer" target="_blank"&gt;some changes&lt;/a&gt; in ECSchemas in PowerPlatform products and iModelJS).&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]Why not use a &lt;a title="Microsoft: Enabling a Data Source for LINQ Querying" href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/enabling-a-data-source-for-linq-querying1" rel="noopener noreferrer" target="_blank"&gt;LINQ data source&lt;/a&gt; to convert query statements into an ECQuery?[/quote]
&lt;p&gt;I guess LINQ did not exist when EC technology was invented ;-)&lt;/p&gt;
&lt;p&gt;But actually ... nobody protect you from implementing own LINQ extension to work with geometry, standard properties and also custom structures defined in EC schemas. But it sounds like long-term complex task.&lt;/p&gt;
[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551175"]Instead, we have a proprietary query API that is poorly documented.[/quote]
&lt;p&gt;The documentation is the biggest problem in my opinion. Even not well structured API can be used efficiently when documented properly. The opposite situation is much worse.&lt;/p&gt;
&lt;p&gt;With regards,&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Jan&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/551175?ContentTypeID=1</link><pubDate>Mon, 28 Oct 2019 10:12:02 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:b28f83ad-48ef-40d4-aba2-391ba1b4d6bf</guid><dc:creator>Jon Summers</dc:creator><description>[quote userid="3014" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/551170"]Is it not possible to query base on library name alone? For example using a SQL like syntax[/quote]
&lt;p&gt;If only that were so!&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t understand the concepts or design that went into the EC query language.&amp;nbsp; I find it hard to use and suspect that I am not alone.&amp;nbsp; Here are some other paths that Bentley Systems might have considered...&amp;nbsp;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If data are stored as XML fragments&amp;nbsp; and schemas are XML, then why not use the XML query language &lt;a title="W3Schools.Com: XQuery" href="https://www.w3schools.com/xml/xquery_intro.asp" rel="noopener noreferrer" target="_blank"&gt;XQuery&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;Comments in the API (&lt;em&gt;ECQuery&lt;/em&gt; struct reference) state that EC queries are analogous to SQL.&amp;nbsp; That analogy is stretched rather thin: Why not make them exactly like SQL by incorporating a &lt;a title="Wikipedia: Domain Specific Language" href="https://en.wikipedia.org/wiki/Domain-specific_language" rel="noopener noreferrer" target="_blank"&gt;domain specific language&lt;/a&gt; (DSL) compiler?&lt;/li&gt;
&lt;li&gt;Why not use a &lt;a title="Microsoft: Enabling a Data Source for LINQ Querying" href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/enabling-a-data-source-for-linq-querying1" rel="noopener noreferrer" target="_blank"&gt;LINQ data source&lt;/a&gt; to convert query statements into an ECQuery?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Instead, we have a proprietary query API that is poorly documented.&amp;nbsp; It&amp;#39;s a combination of classes and text expressions: classes are formally defined and have the usual terse documentation; expressions are not formally defined and have no documentation.&amp;nbsp; Examples are sparse.&lt;/p&gt;
&lt;p&gt;And why are &lt;em&gt;Report&lt;/em&gt; queries different and also undocumented?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/551170?ContentTypeID=1</link><pubDate>Mon, 28 Oct 2019 09:49:44 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:169a6e95-858f-474f-a9c8-3c40fa5baae3</guid><dc:creator>Bruce Reeves SRNS</dc:creator><description>&lt;p&gt;Thanks for the explanation and sample. Is not possible to query base on library name alone? For example (using a SQL like syntax):&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;SELECT Library:* FROM Element WHERE Library=&amp;quot;MyLIbrary&amp;quot;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/550874?ContentTypeID=1</link><pubDate>Fri, 25 Oct 2019 07:18:13 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:c4f65645-4fd0-4b8c-a495-b1404a05524b</guid><dc:creator>Jon Summers</dc:creator><description>[quote userid="3014" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/550765"]DgnCustomItemTypes_SRSFeature:Air__x0020__Tunnel[/quote]
&lt;p&gt;&lt;em&gt;Item Type Library&lt;/em&gt;::&lt;em&gt;Class Name&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;&lt;span style="color:seagreen;"&gt;Get Named Schema&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Here&amp;#39;s a method to get a named schema from the active DGN file...&lt;/p&gt;
&lt;pre&gt;bool  SchemaFactory::GetNamedSchema     (ECN::ECSchemaPtr&amp;amp;  pSchema, WCharCP name)
{
    DgnFileP           pDgnFile  = ISessionMgr::GetActiveDgnFile ();
    const UInt32&amp;amp;      VerMajor  = 1;
    const UInt32&amp;amp;      VerMinor  = 0;
    DgnPlatform::SchemaInfo  schemaInfo  (ECN::SchemaKey (name, VerMajor, VerMinor), *pDgnFile);
    DgnECManagerR      ecMan     = DgnPlatform::DgnECManager::GetManager ();
    pSchema   = ecMan.LocateSchemaInDgnFile (schemaInfo,
            ECN::SchemaMatchType::SCHEMAMATCHTYPE_LatestCompatible);
  return pSchema.IsValid ();
}
&lt;/pre&gt;
&lt;h4&gt;&lt;span style="color:seagreen;"&gt;Create Query for Item Type&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Create a query for a named &lt;em&gt;Item Type&lt;/em&gt; class...&lt;/p&gt;
&lt;pre&gt;ECQueryPtr    ECQueryFactory::CreateQueryForItemType  (WCharCP    itemTypeName)
{
  ECQueryPtr            ecQuery;
  ItemTypeLibraryMgr    libMgr  (L&amp;quot;library name&amp;quot;);
  bool                  found  { libMgr.ExistsInActiveFile () };
  if (found)
  {
    ItemTypeLibraryPtr  pLib  { libMgr.Get () };
    ItemTypeP           itemType = pLib-&amp;gt;GetItemTypeByName(itemTypeName);
    if (nullptr == itemType)
    {
      &lt;span style="color:seagreen;"&gt;// Unable to get Item Type  itemTypeName&lt;/span&gt;
    }
    else
    {
      &lt;span style="color:seagreen;"&gt;// Note reliance on internal library and class names&lt;/span&gt;
      WString  internalName (ItemTypes::GetInternalName (itemType));
      ecQuery  = CreateQuery (pLib-&amp;gt;GetInternalName (), internalName.c_str ());
    }
  }

  return ecQuery;
}
&lt;/pre&gt;
&lt;h4&gt;&lt;span style="color:seagreen;"&gt;Internal Class Names&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Many of the EC interfaces require a class&amp;#39;s &lt;em&gt;internal name&lt;/em&gt; rather than the name that you &amp;amp; I would expect.&amp;nbsp; This article discusses &lt;a title="LA Solutions: EC Display Names and Internal Names" href="http://www.la-solutions.co.uk/content/CONNECT/MicroStationAPI/MicroStationAPI-InstanceIterators.htm#InternalNames" rel="noopener noreferrer" target="_blank"&gt;internal names and how to obtain them&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/550765?ContentTypeID=1</link><pubDate>Thu, 24 Oct 2019 19:19:09 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:1a4b95f5-6ffc-440a-bdbd-897065a9cb0f</guid><dc:creator>Bruce Reeves SRNS</dc:creator><description>[quote userid="2269" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-to-filter-out-schemas/550761"]Are &lt;em&gt;XAttributes&lt;/em&gt; relevant?[/quote]
&lt;p&gt;Yes. I have models that originated in V8 that have XAttributes added to some elements using XMLInstanceAPI::Native. That API is no longer available in CONNECT. When You examine one of these elements, in the Properties dialog they show up as ItemTypes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=" " src="/resized-image/__size/320x240/__key/communityserver-discussions-components-files/343173/2019_2D00_10_2D00_24_5F00_15_2D00_10_2D00_24.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Now I need to (in CONNECT) report on these XAttributes-turned-ItemTypes. I know I can scan the model, and extract ALL the element&amp;#39;s ECClasses, but that returns not only the Item Types, but all the &amp;#39;other&amp;#39; XAttributes (like DgnElementSchema). I&amp;#39;m wondering if there is a way to &amp;quot;filter&amp;quot; the ones returned to ONLY those in the schema I&amp;#39;m interested in.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The ClassName is reported (I assume) in the format Schema::Class. I&amp;#39;d like to find any/all that belong to a specific schema without having to test each Class returned to ensure it&amp;#39;s in the schema I want.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#39;s my impression that when the class name is returned (e.g.&amp;nbsp;&lt;span&gt;DgnCustomItemTypes_SRSFeature:Air__x0020__Tunnel), that since I have a ECClass object, that the Schema and Class names are not really &amp;#39;properties&amp;#39; of the Class, so I&amp;#39;m not sure how filter on them. I am able to filter them using AddSearchClass() and providing the schema and class, but I&amp;#39;d like to accept ALL Classes and don&amp;#39;t want to have&amp;nbsp;&lt;/span&gt;explicitly name each one...If I could supply &amp;#39;*&amp;#39; to get all Classes, that would be perfect, but unfortunately that doesn&amp;#39;t work.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [CONNECT C++] Using a WhereCriterion to filter out schemas</title><link>https://communities.bentley.com/thread/550761?ContentTypeID=1</link><pubDate>Thu, 24 Oct 2019 18:52:02 GMT</pubDate><guid isPermaLink="false">6dad98f5-dbc9-4c4d-a9ba-e9da8dc6aa8e:031c892c-d56c-4bea-886d-8be9b29cc69c</guid><dc:creator>Jon Summers</dc:creator><description>[quote userid="3014" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-tp-filter-out-schemas"]I&amp;#39;m looking at elements that have XAttributes on them[/quote][quote userid="3014" url="~/products/programming/microstation_programming/f/microstation-programming---forum/187538/connect-c-using-a-wherecriterion-tp-filter-out-schemas"][DgnCustomItemTypes_SRSFeature:Air__x0020__Tunnel][/quote]
&lt;p&gt;Your question is about &lt;em&gt;Item Types&lt;/em&gt; and you want to filter on the property values of an &lt;em&gt;Item Type&lt;/em&gt; instance?&amp;nbsp; Are &lt;em&gt;XAttributes&lt;/em&gt; relevant?&lt;/p&gt;
&lt;h4&gt;Query Scope&lt;/h4&gt;
&lt;pre&gt;  using namespace Bentley::DgnPlatform;
  FindInstancesScopeOption option (DgnECHostType::Element);
  //  In entire DGN file
  //scope  = FindInstancesScope::CreateScope (*Utilities::GetActiveDgnFile  (), option);
  //  In active model
  Bentley::DgnPlatform::FindInstancesScopePtr scope  = FindInstancesScope::CreateScope (&lt;br /&gt;                                                         *ISessionMgr::GetActiveDgnModelP (),&lt;br /&gt;                                                         option);
&lt;/pre&gt;
&lt;h4&gt;Compose Query&lt;/h4&gt;
&lt;pre&gt;bool   ECQueryFactory::ComposeCriteria (ECQueryPtr query,
  WCharCP        property,
  WCharCP        filter)
{
  using namespace Bentley::DgnPlatform;
  bool     composed   { false };
  if (query.IsValid())
  {
    WhereExpressionPtr  expression     { WhereExpression::CreatePropertyExpression (property) };
    const bool&amp;amp;         IfMatch        { true };
    const bool&amp;amp;         CaseSensitive  { true };
    WhereCriterionPtr   where;
    WhereCriterion::StringFilterError   error;
    if (RegEx::IsRegEx (filter))
    {
      where = WhereCriterion::CreateRegexFilter (&amp;amp;error, *expression, filter, !CaseSensitive);
    }
    else
    {
      where = WhereCriterion::CreateStringFilter(&amp;amp;error, *expression, filter, IfMatch, !CaseSensitive);
    }
    }
    if (!where.IsValid () &amp;amp;&amp;amp; WhereCriterion::STRING_FILTER_ERROR_InvalidSyntax == error)
    {
      // CreateStringFilter syntax error filter= filter
    }
    else
    {
      query-&amp;gt;SetWhereCriterion (*where);
      composed = query.IsValid ();
    }
  }
  return composed;
}&lt;/pre&gt;
&lt;h4&gt;Execute&lt;/h4&gt;
&lt;pre&gt;DgnECInstanceIterable      ECQueryManager::FindInstances   ()
{
  return ECQueryFactory::FindInstances   (scope_,
                      query_,
                      propertyName_,
                      strFilter_.c_str (),
                      nullptr);
}&lt;/pre&gt;
&lt;p&gt;Thanks to&amp;nbsp;&lt;a href="/members/9e41e1f6_2d00_31fc_2d00_46f5_2d00_8f91_2d00_edeec61fd7a4"&gt;Paul Connelly&lt;/a&gt;&amp;nbsp;for guiding me through that jungle.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>