Bob Horn
Bob Horn

Reputation: 34297

RavenDB: Method not supported: All

I'm getting the exception: Method not supported: All on the last line, below:

private static Expression<Func<InstallationSummary, bool>> GetWhereClause(ApplicationServer appServer, ApplicationWithOverrideVariableGroup appWithGroup)
{
    // If we're getting matches that include CustomVariableGroups (CVGs), then the number of CVGs and the IDs must match.
    return summary => summary.ApplicationServerId == appServer.Id &&
                    summary.ApplicationWithOverrideVariableGroup.ApplicationId == appWithGroup.Application.Id &&
                    summary.ApplicationWithOverrideVariableGroup != null &&
                    summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds != null &&
                    summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds.Count == appWithGroup.CustomVariableGroupIds.Count &&
                    summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds.All(appWithGroup.CustomVariableGroupIds.Contains);
}

Is there another option to use instead of All(), or do I need to bring back the results and loop through them in memory?

public class ApplicationWithOverrideVariableGroup : EntityBase
{
    // More code here
    public List<string> CustomVariableGroupIds { get; set; }
    // More code here
}

Upvotes: 1

Views: 648

Answers (4)

SandRock
SandRock

Reputation: 5573

In Raven.Client 3.0 there is a ContainsAll extension method which seem to be what you are searching for.

namespace Raven.Client.Linq
{
    public static class RavenQueryableExtensions
    {
        // Summary:
        //     Implementation of the Contains ALL operatior
        public static bool ContainsAll<T>(this IEnumerable<T> list, IEnumerable<T> items);
    }
}

Exemple:

string[] parts
var query = session.Query<Foo>()
    .Where(s => s.Keywords.ContainsAll(parts));
return query.ToList();

Upvotes: 0

Jean Hominal
Jean Hominal

Reputation: 16796

One problem that I see is that you are not using the correct overloading of .All.

That is, you are using appWithGroup.CustomVariableGroupIds.Contains which is a method group, and as such can be converted to delegate type Func<..., bool>, but not to the Expression<Func<..., bool>> that is required by Queryable.All. Because of that, you are actually using Enumerable.All, which cannot be supported by a LINQ query provider that wants to translate the query expression.

However, you can write your All clause as a lambda expression instead, and then the correct overload will be called:

summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds.All(cvg => appWithGroup.CustomVariableGroupIds.Contains(cvg));

Upvotes: 0

Peter
Peter

Reputation: 27944

You can translate All to not Any like:

     summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds.All(appWithGroup.CustomVariableGroupIds.Contains);

to

     !summary.ApplicationWithOverrideVariableGroup.CustomVariableGroupIds.Any(x => !appWithGroup.CustomVariableGroupIds.Contains(x));

Upvotes: 0

David
David

Reputation: 10708

One option (albeit possibly inefficient) is that you can always pull the query into memory and then perform .All (or any other Linq method) because the records are already loaded into the application space.

To do this in most cases, you just add .AsEnumerable() on your IQueyable object. Because extension methods are defined statically against the specific type, this means you'll be using the Enumerable extension methods, all of which use a foreach, and thus the query evaluates in-memory.

In this case, it may take some restructuring since you're returning a where clause - such an implementation would have to attach this behaviour to the building of the whole query.

Upvotes: 1

Related Questions