Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
425 views
in Technique[技术] by (71.8m points)

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...