Question

I have a class with a many-many relationship and I'm having problems in properly filtering the results from a query made using Wcf Data Services (through the DataServiceQuery class). This service exposes an Entity Framework 5 model.

This simple query for instance:

from device in devices
select new 
{
    DeviceName = device.Name,
    TestUsers = device
        .Allocations
        .Where(allocation => allocation.User == "testUser")
}

This gives me a NotSupportedException, at runtime:

[NotSupportedException: Constructing or initializing instances of the type <>f__AnonymousType0`4[System.String,System.String,System.String,System.Collections.Generic.IEnumerable`1[Mobiltec.M3S.Model.AllocInfo]] with the expression device.Allocations.Where(_allocation => (_allocation.User == "testUser")) is not supported.]
   System.Data.Services.Client.NonEntityProjectionAnalyzer.VisitMethodCall(MethodCallExpression m) +650
   System.Data.Services.Client.ALinqExpressionVisitor.Visit(Expression exp) +456
   System.Data.Services.Client.ALinqExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original) +107
   System.Data.Services.Client.ALinqExpressionVisitor.VisitNew(NewExpression nex) +52
   System.Data.Services.Client.NonEntityProjectionAnalyzer.VisitNew(NewExpression nex) +226
   System.Data.Services.Client.ALinqExpressionVisitor.Visit(Expression exp) +552
   System.Data.Services.Client.NonEntityProjectionAnalyzer.Analyze(Expression e, PathBox pb, DataServiceContext context) +285
   System.Data.Services.Client.ProjectionAnalyzer.Analyze(LambdaExpression e, PathBox pb, DataServiceContext context) +226
   System.Data.Services.Client.ProjectionAnalyzer.AnalyzeResourceExpression(LambdaExpression lambda, ResourceExpression resource, DataServiceContext context) +58
   System.Data.Services.Client.ProjectionAnalyzer.Analyze(LambdaExpression le, ResourceExpression re, Boolean matchMembers, DataServiceContext context) +335
   System.Data.Services.Client.ResourceBinder.AnalyzeProjection(MethodCallExpression mce, SequenceMethod sequenceMethod, Expression& e) +1000
   System.Data.Services.Client.ResourceBinder.VisitMethodCall(MethodCallExpression mce) +149
   System.Data.Services.Client.ALinqExpressionVisitor.Visit(Expression exp) +456
   System.Data.Services.Client.ALinqExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original) +107
   System.Data.Services.Client.ALinqExpressionVisitor.VisitMethodCall(MethodCallExpression m) +87
   System.Data.Services.Client.ResourceBinder.VisitMethodCall(MethodCallExpression mce) +177
   System.Data.Services.Client.ALinqExpressionVisitor.Visit(Expression exp) +456
   System.Data.Services.Client.ResourceBinder.Bind(Expression e, DataServiceContext context) +57
   System.Data.Services.Client.DataServiceQueryProvider.Translate(Expression e) +252
   System.Data.Services.Client.DataServiceQuery`1.Translate() +37
   System.Data.Services.Client.DataServiceRequest.GetQuerySetCount(DataServiceContext context) +77
   System.Data.Services.Client.DataServiceQueryProvider.ReturnSingleton(Expression expression) +332

If I only project data in there, instead of filtering, like this:

from device in devices
select new 
{
    DeviceName = device.Name,
    AllocatedUsers = device
        .Allocations
        .Select(allocation => allocation.User)
}

It works as expected.

Was it helpful?

Solution

OData's $select clause (which is what the Linq select maps to in the URL) does not support projections that transform property values, at least in OData v3. Projections are used more to reduce the number of properties that you need to work with, rather than to manipulate the property values.

So this is fine and supported:

from device in devices
select new 
{
    DeviceName = device.Name,
    TestUsers = device.Allocations
}

but as soon as you put the .Where clause on Allocations, there is no way to transform that into OData URL syntax.

OTHER TIPS

try to test for equality instead of assigning

.Where(allocation => allocation.User == "testUser")

notice the double ==

actually you are doing assignment in your where statement

from device in devices
select new 
{
    DeviceName = device.Name,
    TestUser = device
        .Allocations
        .Where(allocation => allocation.User = "testUser") // use == for equality
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top