简体   繁体   中英

How to construct a where clause that concatenates two strings with MongoDB in C#

I'm trying to query on firstname + " " + lastname using LINQ.

This is what I tried:

var list =  from x in SomeIQueryable
            where (x.FirstName + " " + x.LastName).StartsWith(searchString)
            select new MyObject
            {
                lastname = x.LastName,
                firstname = x.FirstName
            };
return list.ToList();

With MongoDB, this returns an exception:

System.NotSupportedException: Unable to determine the serialization information for the expression: ((x.FirstName + " ") + x.LastName).
   at MongoDB.Driver.Linq.Utils.BsonSerializationInfoFinder.GetSerializationInfo(Expression node, Dictionary`2 serializationInfoCache)
   at MongoDB.Driver.Linq.Utils.BsonSerializationInfoHelper.GetSerializationInfo(Expression node)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildStringQuery(MethodCallExpression methodCallExpression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildMethodCallQuery(MethodCallExpression methodCallExpression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildQuery(Expression expression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildOrElseQuery(BinaryExpression binaryExpression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildQuery(Expression expression)
   at MongoDB.Driver.Linq.SelectQuery.BuildQuery()
   at MongoDB.Driver.Linq.SelectQuery.Execute()
   at MongoDB.Driver.Linq.MongoQueryProvider.Execute(Expression expression)
   at MongoDB.Driver.Linq.MongoQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at <snip - my code>

It looks like the query parser can't figure out how to build the query correctly from this. I attempted to help it by using the Concat() LINQ extension and that didn't work either:

var list =  from x in SomeIQueryable
            where (string.Concat(x.FirstName, " ", x.LastName)).StartsWith(searchString)
            select new MyObject
            {
                lastname = x.LastName,
                firstname = x.FirstName
            };
return list.ToList();

It didn't like it:

System.ArgumentException: Unsupported where clause: String.Concat(x.FirstName, " ", x.LastName).StartsWith("a").
   at MongoDB.Driver.Linq.PredicateTranslator.BuildQuery(Expression expression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildOrElseQuery(BinaryExpression binaryExpression)
   at MongoDB.Driver.Linq.PredicateTranslator.BuildQuery(Expression expression)
   at MongoDB.Driver.Linq.SelectQuery.BuildQuery()
   at MongoDB.Driver.Linq.SelectQuery.Execute()
   at MongoDB.Driver.Linq.MongoQueryProvider.Execute(Expression expression)
   at MongoDB.Driver.Linq.MongoQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at <snip - my code>

The problem is that MongoDB can't do that as a normal query.

You can't construct a value from multiple fields and then compare it to a value sent via a query:

where (x.FirstName + " " + x.LastName) 

This doesn't have a direct equivalent in MongoDB.

You could potentially execute JavaScript (inefficiently) to perform the concatenation and comparison, or use the aggregation framework (which won't work with LINQ).

Normally, I'd suggest instead you construct a field that contains the data as you need it to be compared (put first + last together, maybe change the case, remove accents, etc.) and then compare it to a string where the same operations have been performed.

If you did combine the strings at runtime, you wouldn't be able to take advantage of MongoDB indexes on the fields, so every document in the collection would need to be scanned.

Or, if possible, consider searching on first and last names independently combined with an and .

Should not be it like this (I could be wrong also :) ).

var list =  from x in SomeIQueryable
            where (x => (x.FirstName + " " + x.LastName).StartsWith(searchString))
            select new MyObject
            {
                lastname = x.LastName,
                firstname = x.FirstName
            };
return list.ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM