2
votes

I have read a lot of previous solutions for this problem but none worked for me.

I have a circular relation between Event and User object:

public class Event : EntityData
{
    [Required]
    [ForeignKey("Creator")]
    public string CreatorId { get; set; }
    public User Creator { get; set; }

    [InverseProperty("ParticipantIn")]
    public virtual ICollection<User> Participants { get; set; }

    [InverseProperty("ManagerIn")]
    public virtual ICollection<User> Managers { get; set; }
}

As you can see I have three references to User from this class: event creator, list of managers, and list of participants.

The user class contains references to Event as well:

public class User: EntityData
{
    [InverseProperty("Participants")]
    public virtual ICollection<Event> ParticipantIn { get; set; }

    [InverseProperty("Managers")]
    public virtual ICollection<Event> ManagerIn { get; set; }
}

Now, the issue is that when I try to serialize an event, like in my createEvent function, it tells me that there is a self referencing loop, that is because when the event is created, I am adding it to the creator's 'ManagerIn' Collection.

That line causes Event->Creator->ManagerIn->Event->Creator->..... LOOP

I tried anything, I also had a version of this code with public virtual User Creator, in order to make it load lazily..

For now, my solution is very not elegant, before returning the event to the client I am performing:

event.Creator = null;

and

event.Managers = null;

in order to avoid a self referencing loop.

What is the right way to solve this kind of problem?

Thanks in advance, Liran!

2
What do you use to serialize it?Evk
If you're using XML stackoverflow.com/questions/5004397/… may be relevantChris
stackoverflow.com/questions/26434738/… may be of interest for jsonChris
There may be others too. Its definitely useful to show us your serialization code and a minimal complete example of your issue (ie give us a program that creates those objects with circular references and then serializes them with whatever method you are using so we can a) see exactly what you are doing and how your error is generated and b) easily modify your code to make it work rather than having to write it all ourselves to confirm any solutions we suggest.Chris

2 Answers

0
votes

I read this is one way to do so.

MyContextEntities.ContextOptions.ProxyCreationEnabled = false;

Otherwise, I would suggest serializing to a different object and avoid serializing your poco's.

0
votes

Because you are specifying the collections as virtual, Entity Framework is Lazy Loading the related entities which is building objects with circular references which the WebAPI JSON serializer does not particularly work well with.

You can disable Lazy Loading for the particular query or queries using

MyEntities.Configuration.LazyLoadingEnabled = false;

Or if you wanted to, remove the virtual keyword from the property declaration. With either of these options, you can then eager load the related collection if required using the Include extension method like so:

MyEntities.Set<Users>()
  .Include(u => u.ManagerIn)
  .Include("ParticipantIn");

(above shows both options for using Include to Eager Load)

The Load method can also be used to explicitly load related entities. Here is a Stack Overflow on Include vs. Load

I've also done something similar to what you have specified for setting the related entity collection to null to prevent that from being included in serialization. For that I'd recommend mapping your POCO / entity to a DTO (data transfer object) first so you can set up something repeatable and avoid accidentally calling SaveChanges() on the same context and unintentionally removing the relationship between your entities in SQL. Automapper is an existing solution that can do this mapping to a DTO or you can write your own Mapper utility class to give yourself a little bit more control.

The last potential option (that I'm aware of) is to adjust the HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandinging settings to ignore reference handling for everything / arrays / objects.

It really depends on your requirements and the rest of the code. Hopefully one of these leads you down the right path and good luck!