3

I'm trying to construct the following nested query such that it will run on my entities in C# but be properly translated through the C# Driver to a MongoDB Query;

lpn = new List<PN> { new PN("/standard"), new PN("/my") };n
Collection.AsQueryable<T>
    (o => o.pns.Any(pf => lpn.Any(pn => pn.n == pf.n))

So that's valid C#. I'm trying to match an array of values against an array of values, but I get this error in the driver stack;

Result Message: 
Test method MyLib.Tests.Models.ProjectTest.DBImportExcelProject threw exception: 
System.NotSupportedException: Unable to determine the serialization information for the expression: System.Collections.Generic.List`1[MyLib.DomainModels.lpn].
Result StackTrace:  
at MongoDB.Driver.Linq.Utils.BsonSerializationInfoFinder.GetSerializationInfo(Expression node, Dictionary`2 serializationInfoCache) in d:\vs11Projects\ThirdParty\mongo-csharp-driver\Driver\Linq\Utils\BsonSerializationInfoFinder.cs:line 64
   at MongoDB.Driver.Linq.Utils.BsonSerializationInfoHelper.GetSerializationInfo(Expression node) in d:\vs11Projects\ThirdParty\mongo-csharp-driver\Driver\Linq\Utils\BsonSerializationInfoHelper.cs:line 48
   at MongoDB.Driver.Linq.PredicateTranslator.BuildAnyQuery(MethodCallExpression methodCallExpression) in d:\vs11Projects\ThirdParty\mongo-csharp-driver\Driver\Linq\Translators\PredicateTranslator.cs:line 133
   at MongoDB.Driver.Linq.PredicateTranslator.BuildMethodCallQuery(MethodCallExpression methodCallExpression) in d:\vs11Projects\ThirdParty\mongo-csharp-driver\Driver\Linq\Translators\PredicateTranslator.cs:line 735
   at MongoDB.Driver.Linq.PredicateTranslator.BuildQuery(Expression expression) in d:\vs11Projects\ThirdParty\mongo-csharp-driver\Driver\Linq\Translators\PredicateTranslator.cs:line 73
...

Which I can appreciate since it's trying to put an $in:[] query into another query.

This is what an object in the collection looks like;

    {
            "_id" : ObjectId("50a5633292c3d22270ac2256"),
            "pns" : [
                    {
                            "n" : "/standard",
                            "ns" : {
                                    "v" : "standard"
                            }
                    }
            ]
    }

So pns is an array of PN types, so I can't simply use Contains() because I don't want to match the whole PN structure, just the n field. I've tried various other constructions.

This is the closest thing I've been able to come up with in the shell;

db.collection.find({
    "pns": {
        "$elemMatch": {
            "n": "/standard",
        }
    }
}).count();

But I can't even find a way to convert that to a Linq expression.

Question Is it possible to build a linq query that matches any array member of lpn within pns but only matching against the n field? Or am I going to have to build these queries by hand?

Update

I think I almost have it. I figure I need to convert to a string array before I can do anything sensible with the query, and I don't think I can do that in Linq. So this works;

var strArray = new[] { "/standard", "/my" };
Collection.AsQueryable<T>(o => o.pns.Any(pn => pn.n.In(strArray)));

which gives me;

{
    "pns": {
        "$elemMatch": {
            "n": {
                "$in": [
                  "/standard",
                  "/my"
                ]
            }
        }
    }
}

But unfortunately, the Driver isn't smart enough to accept this;

Collection.AsQueryable<T>(o => o.pns.Any(pn => pn.n.In(lpn.Select(pfn => pfn.n))));
4

1 回答 1

3

You need to use the Contains linq method...

var strArray = new[] { "/standard", "/my" };
Collection.AsQueryable<T>(o => o.pns.Any(pn => strArray.Contains(pn.n)));

Note, you can do this with a List<string> as well in your case. Anything that implements IEnumerable<T>...

于 2012-11-15T23:28:41.543 回答