Search code examples
c#entity-frameworkcode-first

Entity Framework Circular Reference


Trying this question again because my first attempt was barely coherent :p

So I am super confused and using Entity Framework Code First

I have a Forest class.

I have a Tree class.

Each Forest can have many Trees

When I was trying to serialize I was getting circular reference

public class Forest
{

    public Guid ID { get; set; }  
    public virtual List<Tree> Trees { get; set; }
}
public class Tree
{
    public Guid ID { get; set; }
    public Guid? ForestId {get;set;}

    [ForeignKey("ForestId")]
    public virtual Forest Forest {get;set;}
 }

Every forest has trees but not every tree is in a forest. I struggle with either errors of Multiplicity when doing

@(Html.Raw(Json.Encode(Model)))

Where the model is a Forest

and if I make ForestId a Guid instead of a Guid? I get Circular Reference errors.

I also tried protected override void

OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder) 
{ 
  modelBuilder.Entity<Forest>() 
  .HasMany(x => x.Tree) 
  .WithOptional() 
   .HasForeignKey(y => y.ForestId); 
}

Thanks in advance


Solution

  • Best approach would be you should use DTOs to transfer only the data that you want to the client. The DTOs should have just simple properties so it won't create a circular reference error. At the moment the Forest has List<Trees> Trees and each Tree within Trees has Forest and that Forest again has List<Trees>

    Or

    You can decorate your attributes with ScriptIgnore for properties that you don't want the Json.Encode to serialize and then that wouldn't be sent back to the client.

    http://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute.aspx

    Eg:

    public class Forest
    {    
        public Guid ID { get; set; }  
        public virtual List<Tree> Trees { get; set; }
    }
    public class Tree
    {
        public Guid ID { get; set; }
        public Guid? ForestId {get;set;}
    
        [ForeignKey("ForestId")]
        [ScriptIgnore]
        public virtual Forest Forest {get;set;}
     }
    

    Edit:

    Along with ScriptIgnore you should also remove virtual from Forest and Trees and that would work. I've tested it. However, I wouldn't advise that because virtual keyword is what does the Lazy loading. Hence as I said you need to create DTOs based on these Models and only send in DTO to client.