Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The 'TypeIs' expression with an input of type 'Domain.Entities.Request' and a check of type 'Domain.Entities.Base' is not supported

Tags:

c#

.net

linq

api

odata

I'm getting this error:

The 'TypeIs' expression with an input of type 'Domain.Flood.Entities.Things.SomeObject' and a check of type 'Domain.Entities.Base' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.

I'm trying to call my OData API and Expand the CreatedBy property on my object. The CreatedBy Property is in the base class and is a type of User. So my Base Class looks like this:

[DataContract(Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
    public abstract class Base
    {    
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public string Description { get; set; }    

        private User createdBy;    
        [DataMember]
        public virtual User CreatedBy
        {
            get
            {
                return createdBy;
            }
            set
            {
                createdBy = value;
            }
        } 
    }

When I try to get my widget that inherits from the base class, and I want to also include the User object called CreatedBy, I get this error. If I don't expand the CreatedBy object I don't get the error. Here's the weird part, I have another User property not on the base class but up in my SomeObject class called AssignedTo. If I expand on that, everything is peachy. So Expand the User object on the base class, no bueno. Expand the User object up a few levels, bueno.

     {
         Container.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequest);
         ViewBag.Data = Container.SomeObject.Expand("Address, CreatedBy").ToList();
         return View();
     }

Here's the stack trace:

Exception Details: System.Data.Services.Client.DataServiceClientException: <?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
 <m:code />
 <m:message xml:lang="en-US">An error has occurred.</m:message>
 <m:innererror>
   <m:message>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/atom+xml; charset=utf-8'.</m:message>
   <m:type>System.InvalidOperationException</m:type>
   <m:stacktrace></m:stacktrace>
   <m:internalexception>
     <m:message>The 'TypeIs' expression with an input of type 'Domain.Flood.Entities.Things.SomeObject' and a check of type 'Domain.Entities.Base' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.</m:message>
     <m:type>System.NotSupportedException</m:type>
     <m:stacktrace>   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.GetIsOrAsTargetType(ExpressionType operationType, Type toClrType, Type fromClrType)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.IsTranslator.TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConditionalTranslator.TypedTranslate(ExpressionConverter parent, ConditionalExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MemberInitTranslator.TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MemberInitTranslator.TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MemberInitTranslator.TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding&amp; binding)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression&amp; source, DbExpressionBinding&amp; sourceBinding, DbExpression&amp; lambda)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()&#xD;
  at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)&#xD;
  at System.Data.Entity.Core.Objects.ObjectQuery`1.&lt;&gt;c__DisplayClassb.&lt;GetResults&gt;b__a()&#xD;
  at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)&#xD;
  at System.Data.Entity.Core.Objects.ObjectQuery`1.&lt;&gt;c__DisplayClassb.&lt;GetResults&gt;b__9()&#xD;
  at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)&#xD;
  at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)&#xD;
  at System.Data.Entity.Core.Objects.ObjectQuery`1.&lt;System.Collections.Generic.IEnumerable&lt;T&gt;.GetEnumerator&gt;b__0()&#xD;
  at System.Lazy`1.CreateValue()&#xD;
  at System.Lazy`1.LazyInitValue()&#xD;
  at System.Lazy`1.get_Value()&#xD;
  at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()&#xD;
  at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)&#xD;
  at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)&#xD;
  at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)&#xD;
  at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)&#xD;
  at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)&#xD;
--- End of stack trace from previous location where exception was thrown ---&#xD;
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)&#xD;
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult()&#xD;
  at System.Web.Http.WebHost.HttpControllerHandler.&lt;WriteBufferedResponseContentAsync&gt;d__14.MoveNext()</m:stacktrace>
   </m:internalexception>
 </m:innererror>
</m:error>

Reading the error message, I can see that Linq to Entities is trying to convert one thing to another, but that's so far under the hood that I really don't know.

One other thing that I noticed is that my OData metadata is showing everything, not just the stuff that has data contracts. It used to only include classes with data contracts. That's weird right? I went through my source control to see what changed in the last few changesets and I don't see anything having to do with my Base class, Users class or my SomeObject Class. Nothing having to do with my API either.

If I can be more clear, please let me know. I feel like I'm leaving something out.

like image 958
MayorAwesome Avatar asked Jan 14 '14 23:01

MayorAwesome


1 Answers

If you read the error carefully:

The 'TypeIs' expression with an input of type 'Domain.Flood.Entities.Things.SomeObject' and a check of type 'Domain.Entities.Base' is not supported.

This means that OData tries a query that makes EF generate one with a "TypeIs" function which is fine in itself, but both operands of TypeIs have to be either an Entity Type or a Complex type:

Only entity types and complex types are supported in LINQ to Entities queries.

That is, in the EF DbContext, using the ModelBuilder, you have to make sure both SomeObject and Base are known to the context either as Entity types or Complex types. Here's to do it with Fluent API:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Base>(); //EF should crawl and configure all derived types as well.
}

Also, pay special attention when using DbModelBuilder.Ignore() not to ignore any important type.

UPDATE:

You can also tell OData to treat all super class inherited properties as the inherited type's own with ODataConventionModelBuilder :

With System.Web.OData:

modelBuilder.EntityType<SomeObject>().DerivesFromNothing();

With System.Web.Http.OData:

modelBuilder.Entity<SomeObject>().DerivesFromNothing();
like image 122
Jerther Avatar answered Oct 03 '22 00:10

Jerther