简体   繁体   中英

Entity Framework Core 6 eager loading include too many level

After upgrading my project to EF Core 6, I have a strange behaviour:

I have two classes in my dbcontext with a many-to-many relation - like this:

public class SiteImage
{
    public int siteImageId { get; set; }
    public string siteImageUrl { get; set; }
        ...
    public ICollection<SiteImageCategory> categories { get; set; }
}

public class SiteImageCategory
{
    public int siteImageCategoryId { get; set; }
    public string name { get; set; }
    public ICollection<SiteImage> images { get; set; }
}

They are mapped to tables in DBContext

public DbSet<SiteImage> images { get; set; }
public DbSet<SiteImageCategory> categories { get; set; }

If I want to retrieve all images with this code:

var images = await _context.images.ToListAsync();

I have get the list of images with all categories = null and and that's what I expected.

But if I want to include categories using eager loading, like this:

var images = await _context.images
                           .Include(x => x.categories)
                           .ToListAsync();

I get the list with categories, but any category includes all related images, with a related categories in an infinite loop (stopped by ReferenceHandler.IgnoreCycles setting).

I would have expected the code to stop at the category level, according to include statement.

What am I doing wrong?

Thanks

I would have expected to stop at the category level, according to include stantment.

It did. However when each SiteImageCategory is loaded, if its SiteImage is already in the change tracker, the relationship will be "fixed up". So if you load all the SiteImages you will already have each SiteImageCategory's SiteImages in the Change Tracker, and the inverse navigation property collection will be populated.

ReferenceHandler.IgnoreCycles

This is nothing to do with EF nor anything that it did wrong. You're serializing your db entity graph, which you should avoid doing because it's a bidirectionally linked graph.

An image X has categories Y, Z etc and those categories have images, one of which is image X, which..

has categories Y, Z etc and those categories have images, one of which is image X, which..

has categories Y, Z etc and those categories have images, one of which is image X, which..

has categories Y, Z etc and those categories have images, one of which is image X, which..

And so on.

As the serializer serializes the graph it will travel these paths and go into a cycle, only stopping if it can keep track of everything it's ever seen before

If you don't want to rely on that then there are other options:

  • disconnect the reverse relationship - empty out all the.Images collections in every Category. This means that you can start from an image and travel to a category but no category ever links back to an image
  • don't serialize a db entity graph at all; map it onto a (set of) viewmodels that do not have cycles (image viewmodel might has-some category viewmodel, but a category viewmodel doesn't has-a/some image viewmodels)

I'd say it's probably most common to take the latter approach, and don't serialize db entities

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM