TheVillageIdiot
TheVillageIdiot

Reputation: 40517

EF loading virtual navigation property without accessing

I have following models:

public class Category
{
    public virtual ICollection<Product> Products{get;set;}
    public Product()
    {
        Products = new HashSet<Product>();
    }
}

public class Product
{
    public Guid CategoryId{get;set;}
    public virtual Category {get;set;}
}

Now if I execute following statement:

var list = await UoW.Categories.Query.Where(x=>x.Name.Contains("Mob")).ToListAsync();

and return list as JSON from MVC controller action. It throws following exception:

A circular reference was detected while serializing an object of type 
'System.Data.Entity.DynamicProxies.Category_7C2191CFExxxxxxx'.

It is happening because Products collection is not null and each Product in turn contains Category.

What is the reason for virtual properties getting uploaded automatically?

EDIT:- It turns out Json Serializer was accessing properties and causing EF to load them. I have turned LazyLoading off as suggested by haim770.

Upvotes: 2

Views: 730

Answers (2)

Robert Graves
Robert Graves

Reputation: 2320

WCF tries to walk your objects and serialize the whole object graph. If you have lazy loading enabled (as it is by default), it will get stuck in this circular reference.

One option is to turn off Lazy loading as haim770 suggests. Another is to return Data Transfer Objects rather than returning your EF objects directly.

It is also possible to return your object graph with the circular references intact. However you'll need to create a custom DataContractSerializerOperationBehavior and a custom Attribute to apply that behavior. Sowmy Srinivasan's blog post has the full details.

Upvotes: 0

haim770
haim770

Reputation: 49105

The reason is the Entity Framework Proxy that is intercepting the access call to your Products property and automatically populates it.

You can explicitly turn Lazy-Loading off though:

context.Configuration.LazyLoadingEnabled = false;

You can also project your Category list into a new list and only populate the desired properties. For example:

var list = await UoW.Categories.Query.Where(x=>x.Name.Contains("Mob"))
                                     .Select(x => new Category {
                                             Id = x.Id,
                                             Name = x.Name
                                     }).ToListAsync();

Upvotes: 1

Related Questions