1

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
}
Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • 1
    Show your `InstallationSummary` class so we can see what `CustomVariableGroupIds` is. – haim770 Dec 17 '14 at 15:03
  • I added it to my question. – Bob Horn Dec 17 '14 at 15:06
  • `All` can always be replaced by `Any` with a negated argument. If that's not supported, you can replace it by `Where` followed by `Any()`. Would that possibly help? – chiccodoro Dec 17 '14 at 15:09
  • [Apparently `Any` and `All` are not supported inside expressions](http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression_methods(v=vs.110).aspx). Perhaps calling the Linq extension method manually would do the trick (i.e. transform the `All` into a plain `Call` -- though obviously this would require things to be in memory)? – Cameron Dec 17 '14 at 15:12
  • Could you retry your code by using a lambda expression in `All` instead? The way I see it, you are using the `Enumerable.All` extension method, whereas the extension method that has a chance of working is `Queryable.All`. (That is, try writing `.All(cvg => appWithGroup.CustomVariableGroupIds.Contains(cvg))` – Jean Hominal Dec 17 '14 at 15:13

4 Answers4

1

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.

David
  • 10,458
  • 1
  • 28
  • 40
  • I had to go with the in-memory approach because RavenDB wouldn't work with `All()` or the negated `Any()`. Thanks. – Bob Horn Dec 17 '14 at 17:00
0

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));
Cameron
  • 96,106
  • 25
  • 196
  • 225
Peter
  • 27,590
  • 8
  • 64
  • 84
  • 1
    "All" is not the same as "not any" unless you also negate the inner expression. Example: "No single apple is blue" does not mean "all apples are blue", but "no single apple is a colour other than blue" does. – Cameron Dec 17 '14 at 15:14
  • While not very intuitive (because of the multiple !s), it's at least still just that one line of code. Let me see if I can get that to work... – Bob Horn Dec 17 '14 at 15:21
  • What's cool about this answer is that ReSharper asks me if I want to simplify it and convert it to the code that Jean provided. I can't, because RavenDB doesn't support it, but it's at least an indication that it's equivalent code. – Bob Horn Dec 17 '14 at 15:57
  • Apparently RavenDB doesn't allow this approach either. I get: `System.InvalidOperationException: Cannot process negated Any(), see RavenDB-732 http://issues.hibernatingrhinos.com/issue/RavenDB-732` – Bob Horn Dec 17 '14 at 15:59
0

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));
Jean Hominal
  • 16,518
  • 5
  • 56
  • 90
  • I tried that and I still get `Method not supported: All`. Perhaps RavenDB simply doesn't support this yet. – Bob Horn Dec 17 '14 at 15:53
  • I am also realizing that my explanation is slightly wrong - that is, because `CustomVariableGroupIds` is probably not an `IQueryable`, `Queryable.All` cannot be used. – Jean Hominal Dec 17 '14 at 15:56
0

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();
SandRock
  • 5,276
  • 3
  • 30
  • 49