Supported methods and operators for xConnect search

Version: 9.2

xConnect search does not implement all of IAsyncQueryable<T> and will throw a Sitecore.XConnect.Search.YourLinqIsTooStrongException exception if you try to use a method that is not supported. The following list applies to both contact and interaction search unless explicitly stated.

Refer to the xConnect Client API for an overview of synchronous and asynchronous extension methods.

Supported

The following extension methods are supported:

  • .Where()

  • .Any() (Simple - see the “Azure Search: List field limitations” section for restrictions)

  • .ToArray()

  • .ToList()

  • .Count()

  • .OrderBy()

  • .OrderByDescending()

  • .ThenBy()

  • .ThenByDescending()

  • .OfType<T>()

  • .Skip() and .Take() (See search result pagination)

  • .FirstOrDefault()

  • .First()

  • .Single()

  • .SingleOrDefault()

  • == and !=

  • < and >

  • <= and >=

  • && and ||

xConnect-specific extensions

  • .GetBatchEnumerator() / .GetBatchEnumeratorSync()

  • .ToSearchResults()

  • .WithExpandOptions()

  • .AsEnumerable() (synchronous only)

Not supported

The following extension methods are not supported:

  • Contains

  • StartsWith

  • EndsWith

  • ToString

  • Equals

Note

There is no Like() extension method.

The following scenarios are not supported in any search provider for xConnect search:

Custom methods inside search expressions

The xConnect Client API does not support custom method calls inside LINQ query expressions. You will receive a Sitecore.XConnect.Search.YourLinqIsTooStrongException exception.

Search for null values

It is currently not possible to check if a facet is null. For example:

RequestResponse
var notWebVisits = client.Interactions.Where(c => c.WebVisit() == null);

Search by Timespan in custom event properties

The following query (using a custom Timespan property) will not work:

RequestResponse
var interactions = await _client.Contacts.Where(c => c.Interactions.Any(i => i.Events.OfType<CampaignEvent>().Any(e => e.CustomCampaignTimespan == TimeSpan.Zero)));

You can still use the default Duration property on events. This restriction only applies to events, not facets.

First, FirstOrDefault, Last, LastOrDefault, or Count inside a LINQ expression expression

The following query will not work because it uses First():

RequestResponse
var interactions = await _client.Interactions.Where(i => i.Events.First().EngagementValue == 11).ToList();

The following query will not work because it uses FirstOrDefault():

RequestResponse
var contacts = await _client.Contacts.Where(contact => contact.Interactions.OrderByDescending(x => x.StartDateTime).FirstOrDefault().WebVisit().SiteName == "value");

The following query will not work because it uses Last():

RequestResponse
var contacts = await _client.Contacts.Where(contact => contact.Interactions.Last().WebVisit().SiteName == value);

Timespan

Timespan cannot be used with a query that combines the OfType operator AND a Timespan property (e.g. Hours, Minutes, Seconds, etc.).

This works:

RequestResponse
events.OfType<SomeEventType>(e => e.SomeTypeTimeSpanField > TimeSpan.FromHours(2))

This does not work:

RequestResponse
events.OfType<SomeEventType>(e => e.SomeTypeTimeSpanField.Hours > 10)

Repeated names in paths to complex lists

The following query is not supported because Path.To.Nested is the same for both lists:

  • i.Scores().Scores.Any(s=>s.Path.To.Nested.Any())

  • i.ProfileScores().ProfileScores.Any(s=>s.Path.To.Nested.Any())

The following limitations are specific to the Azure Search provider for xConnect search:

  • contact.Interactions.Any(): Joins are not supported by the Azure Search provider. For more information, see Work with search and Search contacts (includes examples with and without joins).

    Important

    This limitation affects which segmentation rules can be used with Azure Search. For example, you cannot filter contacts by email events (such as opening and email or clicking a link).

The following list relates to complex type limitations in Azure Search.

9.0 Update 2

9.0 Update 2 introduces improvements to comparisons within list of complex types.

Not supported

For nested lists of strings, enums, and Guids, the following are not supported:

  • !=

  • >

  • >=

  • <

  • <=

  • !=

The following queries are not supported:

  • c=>c.SomeFacet().SomeList.Any(e=>e!="hello")

  • c=>c.SomeFacet().SomeList.Any(e=>e!="hello"||e!="world")

The following queries are supported:

  • c=>c.SomeFacet().SomeList.Any(e=>e=="hello")

  • c=>c.SomeFacet().SomeList.Any(e=>e=="hello"||e=="world")

Supported

  • For nested lists of complex types or other simple types such as int or float, all comparison types are supported:

    • ==

    • ||

    • &&

    • !

    • >

    • >=

    • <

    • <=

    • !=

    The following queries are supported:

    • :c=>c.SomeFacet().SomeList.Any(e=>e.Property1>2)

    • c=>c.SomeFacet().SomeList.Any(e=>e.Property1!=2)

    • c=>c.SomeFacet().SomeList.Any(e=>e.Property1==2&&e.Property2=="string")

    • c=>c.SomeFacet().SomeList.Any(e=>e.Property1==2||e.Property2=="string")

  • For lists that contain another list, it is possible to use a nested Any() to reach the nested list - for example: someList.Any(v=>v.NestedList.Any(u=>u.SomeField==2))

  • For nested lists of strings, enums, and Guids, == and || may be used inside the Any() predicate. The following queries are supported:

    • c=>c.SomeFacet().SomeList.Any(e=>e=="hello")

    • c=>c.SomeFacet().SomeList.Any(e=>e=="hello"||e=="world")

  • The Any() that follows an OfType<T> call can refer to fields of the exact type or the base class. The following queries are supported:

    • i=>i.Events.OfType<Outcome>().Any(o=>o.MonetaryValue>10)

    • i=>i.Events.OfType<Outcome>().Any(o=>o.DefinitionId==someId)

9.0 Initial Release and 9.0 Update 1

Not supported

For nested lists, only == may be used inside the Any() predicate - for example, MyListProperty.Any(v=>v.SomeField==2). The following are not supported:

  • &&

  • ||

  • !

  • >

  • >=

  • <

  • <=

  • !=

As a result, the following queries are not supported:

  • :c=>c.SomeFacet().SomeList.Any(e=>e.Property1>2)

  • c=>c.SomeFacet().SomeList.Any(e=>e.Property1!=2)

  • c=>c.SomeFacet().SomeList.Any(e=>e.Property1==2&&e.Property2=="string")

  • c=>c.SomeFacet().SomeList.Any(e=>e.Property1==2||e.Property2=="string") (this query can be rewritten as c=>c.SomeFacet().SomeList.Any(e=>e.Property1==2)||c=>c.SomeFacet().SomeList.Any(e=>e.Property2=="string"), which is supported)

The Any() that follows an OfType<T> call can only refer to fields of the exact type that was specified - not the base class. The following queries are not supported:

  • i=>i.Events.OfType<Outcome>().Any(o=>o.MonetaryValue>10) (Even though MonetaryValue is a property of Outcome, Any() cannot be used with >)

  • i=>i.Events.OfType<Outcome>().Any(o=>o.DefinitionId==someId) (DefinitionId is a property of a base class, not of Outcome)

Supported

The following queries are supported:

  • c=>c.InteractionCache().InteractionCaches.Any(i=>i.Goals.Any(i=>i.DefinitionId==1234567))

  • For lists that contain another list, it is possible to use a nested Any() to reach the nested list - for example: someList.Any(v=>v.NestedList.Any(u=>u.SomeField==2))

Do you have some feedback for us?

If you have suggestions for improving this article,