realm-dotnet
realm-dotnet copied to clipboard
[Unity][Bug] string.Contains() throws NotSupportedException in Unity 2021.2
Realm Version: 10.7.1 Unity Version: 2021.2.5f1 Client OS: Windows 10 Pro 21H1 19043.1348
I recently upgraded my Unity version from 2020.3 to 2021.2. Since the update, calling string.Contains() in a realm query throws a NotSupportedException. With Unity 2020.3 results get returned as expected and no exception is thrown. My model looks like this:
public class Tag : RealmObject
{
[PrimaryKey]
public int Uid { get; set; }
[Required]
public string Name { get; set; }
}
and the class executing the query like this:
using Realms;
using System.IO;
using System.Linq;
using UnityEngine;
public class RealmExample : MonoBehaviour
{
private static Realm realm;
private void Awake()
{
RealmConfiguration config = new(Path.Combine(Application.dataPath, "database.realm"))
{
IsReadOnly = true,
Schema = new[]
{
typeof(Tag),
},
SchemaVersion = 11ul
};
realm = Realm.GetInstance(config);
}
[ContextMenu("QueryTags")]
public void QueryTags()
{
string substring = "T";
IQueryable<Tag> tags = realm.All<Tag>()
// The line below is the one causing the exception
.Where(t => t.Name.Contains(substring, System.StringComparison.OrdinalIgnoreCase));
foreach (var t in tags)
{
print(t.Name);
}
}
}
I receive the following exception:
NotSupportedException: The left-hand side of the Call operator must be a direct access to a persisted property in Realm.
Unable to process 'value(RealmExample+<>c__DisplayClass2_0).substring'.
Realms.RealmResultsVisitor.GetColumnName (System.Linq.Expressions.MemberExpression memberExpression, System.Nullable`1[T] parentType) (at <5ee71c2d3038455ca732a3febcca3879>:0)
Realms.RealmResultsVisitor.VisitMethodCall (System.Linq.Expressions.MethodCallExpression node) (at <5ee71c2d3038455ca732a3febcca3879>:0)
System.Linq.Expressions.MethodCallExpression.Accept (System.Linq.Expressions.ExpressionVisitor visitor) (at <61774763be294c9f8e2c781f10819224>:0)
System.Linq.Expressions.ExpressionVisitor.Visit (System.Linq.Expressions.Expression node) (at <61774763be294c9f8e2c781f10819224>:0)
Realms.RealmResultsVisitor.VisitMethodCall (System.Linq.Expressions.MethodCallExpression node) (at <5ee71c2d3038455ca732a3febcca3879>:0)
System.Linq.Expressions.MethodCallExpression.Accept (System.Linq.Expressions.ExpressionVisitor visitor) (at <61774763be294c9f8e2c781f10819224>:0)
System.Linq.Expressions.ExpressionVisitor.Visit (System.Linq.Expressions.Expression node) (at <61774763be294c9f8e2c781f10819224>:0)
Realms.RealmResults`1[T].GetOrCreateHandle () (at <5ee71c2d3038455ca732a3febcca3879>:0)
System.Lazy`1[T].ViaFactory (System.Threading.LazyThreadSafetyMode mode) (at <00c558282d074245ab3496e2d108079b>:0)
System.Lazy`1[T].ExecutionAndPublication (System.LazyHelper executionAndPublication, System.Boolean useDefaultConstructor) (at <00c558282d074245ab3496e2d108079b>:0)
System.Lazy`1[T].CreateValue () (at <00c558282d074245ab3496e2d108079b>:0)
System.Lazy`1[T].get_Value () (at <00c558282d074245ab3496e2d108079b>:0)
Realms.RealmCollectionBase`1+Enumerator[T]..ctor (Realms.RealmCollectionBase`1[T] parent) (at <5ee71c2d3038455ca732a3febcca3879>:0)
Realms.RealmCollectionBase`1[T].GetEnumerator () (at <5ee71c2d3038455ca732a3febcca3879>:0)
RealmExample.QueryTags () (at Assets/RealmExample.cs:32)
My current workaround is to use Like() instead of Contains() like this
// Added the asterisk to match the behaviour of Contains()
string substring = "*T*";
IQueryable<Tag> tags = realm.All<Tag>()
// This works fine
.Where(t => t.Name.Like(substring, false));
Thank you for the report. I can reproduce the issue. And I can confirm that, as reported, it does not happen with version 2020.3. I'll start looking into it.
Hi, are there any updates on this issue? I'm currently hitting the same issue in a Xamarin app. For me it seems to be a problem with the combination of using a variable for the text to search and the case insensitive query.
var searchText = "test";
// works
var result = realm.All<Person>().Where(x =>
x.FirstName.Contains(searchText))
.ToList();
// works
result = realm.All<Person>().Where(x =>
x.FirstName.Contains("test", StringComparison.OrdinalIgnoreCase))
.ToList();
// doesn't work
result = realm.All<Person>().Where(x =>
x.FirstName.Contains(searchText, StringComparison.OrdinalIgnoreCase))
.ToList();
We haven't been able to take a look yet, but you could try working around it by using Like
(as long as your searchText
doesn't contain *
or ?
). An equivalent expression would be something like: .Where(x => x.FirstName.Like($"*{searchText}*", true)
. Alternatively, you can use the string query syntax like: .Filter("FirstName CONTAINS[c] $0", searchText)
.
This is giving us test failures in a dotnet6 test project, on use of .Contains(s, StringComparison.CurrentCultureIgnoreCase)
. It is OK in 10.11.2 but throws in 10.12.0 and above.
System.MissingMethodException : Method not found: 'Boolean Realms.StringExtensions.Contains(System.String, System.String, System.StringComparison)'.
.NET 6 has a built-in Contains(string, StringComparison)
API, so you don't need to use the extension method from Realms.StringExtensions
.
OK thanks. We are on netstandard2.0 at the moment (for xamarin compatibility) so don't have access to this - just running the tests on dotnet6. We can probably stay on 10.11.2 for quite a long time until we can migrate to dotnet6+ so it's not urgent.
Closing this as duplicate of https://github.com/realm/realm-dotnet/issues/3134