I have a project I am working on that has a Order entity that has a navigation property for OrderITems:
public class Order
{
public int OrderId { get; set; }
public int CustomerId { get; set; }
public virtual ICollection<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
public int OrderId { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public virtual Order Order { get; set; }
}
If I query the OrderItems like so:
http://mysvc.com/mysvc/OrderItems?$expand=Order&$filter=ProductId eq 1234
It works well but I ultimately need to bind to the Order only. So, I would like to project like this:
http://mysvc.com/mysvc/OrderItems?$expand=Order&$filter=ProductId eq 1234&$select=Order
However, I receive a 'Not Implemented' exception.
Th project is using an EntityFramework code first 4.1 data provider and all of the wiring "appears" correct. The only thing extra I added was routing to produce the clean restful uris and support for the $format option via a IDispatchMessageInspector.
Ok, Thanks to Vitek's input I was able to get a more complete exception:
<error>
<code/>
<message xml:lang="en-US">Not Implemented</message>
<innererror>
<message>Unable to create a constant value of type 'System.Data.Services.Internal.ProjectedWrapper1'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
</message>
<type>System.NotSupportedException</type>
<stacktrace> at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.ConditionalTranslator.TypedTranslate(ExpressionConverter parent, ConditionalExpression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Objects.ELinq.ExpressionConverter.Convert()
at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.IEnumerable.GetEnumerator()
at System.Data.Services.Internal.ProjectedWrapper.EnumerableWrapper.System.Collections.IEnumerable.GetEnumerator()
at System.Data.Services.WebUtil.GetRequestEnumerator(IEnumerable enumerable)
</stacktrace>
</innererror>
</error>
If this is using EF Code First it needs to define the service as DataService and override the CreateDataSource to use the trick described in this article in section #5: http://social.technet.microsoft.com/wiki/contents/articles/5234.aspx
Otherwise WCF DS treats the DbContext as a reflection provider would and runs queries intended for LINQ to Objects. This mostly works, but for more complicated queries it sometimes breaks. If the WCF DS knows it runs agains EF, it creates queries for EF which will work always.