Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OData Exception: A recursive loop of complex types is not allowed

I expose a complex type through OData. The class is like this:

public class RemoteFile 
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Resource { get; set; }

    public virtual ICollection<RemoteFile> RelatedFiles { get; set; }
}

And I expose it through OData:

    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.ComplexType<RemoteFile>();

Here is what I got when I start the project:

An exception of type 'System.ArgumentException' occurred in System.Web.Http.OData.dll but was not handled in user code

Additional information: The complex type 'RemoteFile' has a reference to itself through the property 'RelatedFiles'. A recursive loop of complex types is not allowed.

If there is a handler for this exception, the program may be safely continued.

Any suggestion is welcomed.

like image 936
maomao Avatar asked Feb 03 '14 18:02

maomao


3 Answers

It sounds like it makes more sense for RemoteFile to be an entity type, not a complex type. Entity types can have properties that point to the originating type, which is how you've set up RemoteFile. Your definition of the type also has a key property, which is used for entity types, not complex types. (Think of complex types as a convenient way to group a bunch of scalar properties. Entity types are the first-class types of your system where each instance can be uniquely identified.)

So instead of this:

modelBuilder.ComplexType<RemoteFile>();

Try this:

modelBuilder.EntitySet<RemoteFile>(“RemoteFiles”);

That line will create both the entity type RemoteFile and the entity set RemoteFiles. An entity set is the container for all the instances of an entity type.

So why is recursion allowed for entity types but not complex types? When you ask for an entity, by default the server won't fetch the data of referenced entities. You can explicitly ask for the data of a referenced entity by using $expand in the query, but you can't expand infinitely. On the other hand, complex values will always be included when you ask for their parent. So if you have a circular complex value, you'll create a stack overflow when you try to serialize it.

like image 134
Jen S Avatar answered Nov 09 '22 15:11

Jen S


Do you need to explicitly ignore the navigation property by any chance?

modelBuilder.ComplexType<RemoteFile>().Ignore(x => x.RemoteFile);

Hope that helps :)

like image 22
Malcolm Swaine Avatar answered Nov 09 '22 15:11

Malcolm Swaine


I had the same problem. I had a model with more than 100 entities, and I tried to add only two, for make tests.

The solution: ADD ALL ENTITIES to ODataConventionModelBuilder, something like this:

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("Entity1");
builder.EntitySet<Entity2>("Entity2");
builder.EntitySet<Entity3>("Entity3"); 

//... and thus for ALL YOUR ENTITIES.

// If you don't want to expose any entity like EntitySet, simply add to builder like EntityType:
builder.EntityType<Entity4>("Entity4");

Even if you do not add entities, the builder scans all types like Complex Types, and relationships fail. Therefore it is necessary to specify that all scanned types are Entities.

If you don't want to expose all like EntitySet, you can add to builder like EntityType, and your client reference will use this class but not will give you access to a EntitySet (CRUD Operations). This Entities only can be used indirectly through relationships of exposed entities.

like image 2
Johan Alzate Avatar answered Nov 09 '22 16:11

Johan Alzate