EF Core Eager Loading nested collections












4















I'm trying to load a related modal in Entity Framework Core but for some reason there's a nested collection being loaded when I haven't asked for it in my Include() call.



Here's my two models -



Driver.cs



public partial class Driver : IBaseEntity
{
public short DriverId { get; set; }
public string Surname { get; set; }
public string Initials { get; set; }
public byte DriverStatusTypeId { get; set; }

public DriverStatusType DriverStatusType { get; set; }
}


DriverStatusType.cs



public partial class DriverStatusType
{
public DriverStatusType()
{
Drivers = new HashSet<Driver>();
}

public byte DriverStatusTypeId { get; set; }
public string DriverStatusTypeName { get; set; }
public string Description { get; set; }

public ICollection<Driver> Drivers { get; set; }
}


DriversService.cs



public class DriverService : IDriverService
{
public DriverService(MyContext context)
{
Context = context;
}

public MyContext Context { get; }

public async Task<IEnumerable<Driver>> GetAllDrivers()
{
var drivers = await Context
.Drivers
.Include(d => d.DriverStatusType)
.toListAsync();

return drivers;
}

public async Task<Driver> GetDriverById(int id)
{
var driver = await Context
.Drivers
.Include(d => d.DriverStatusType)
.Where(d => d.DriverId == id)
.FirstOrDefaultAsync();

return driver;
}
}


Now when I call the GetDriverById(int id) method from my controller I get back what I'm expecting -



{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers":
}
}


However the GetAllDrivers() method is returning the nested drivers collection which means the data I'm getting back is huge -



[
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"displayText": "Tony Stark",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": [
{
"driverId": 2,
"surname": "Rogers",
"initials": "S",
"driverStatusTypeId": 2
},
{
"driverId": 3,
"surname": "Romanoff",
"initials": "N",
"driverStatusTypeId": 2
},
{
"driverId": 4,
"surname": "Banner",
"initials": "B",
"driverStatusTypeId": 2
},
...


I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?










share|improve this question























  • Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

    – Adam Vincent
    Nov 26 '18 at 12:34
















4















I'm trying to load a related modal in Entity Framework Core but for some reason there's a nested collection being loaded when I haven't asked for it in my Include() call.



Here's my two models -



Driver.cs



public partial class Driver : IBaseEntity
{
public short DriverId { get; set; }
public string Surname { get; set; }
public string Initials { get; set; }
public byte DriverStatusTypeId { get; set; }

public DriverStatusType DriverStatusType { get; set; }
}


DriverStatusType.cs



public partial class DriverStatusType
{
public DriverStatusType()
{
Drivers = new HashSet<Driver>();
}

public byte DriverStatusTypeId { get; set; }
public string DriverStatusTypeName { get; set; }
public string Description { get; set; }

public ICollection<Driver> Drivers { get; set; }
}


DriversService.cs



public class DriverService : IDriverService
{
public DriverService(MyContext context)
{
Context = context;
}

public MyContext Context { get; }

public async Task<IEnumerable<Driver>> GetAllDrivers()
{
var drivers = await Context
.Drivers
.Include(d => d.DriverStatusType)
.toListAsync();

return drivers;
}

public async Task<Driver> GetDriverById(int id)
{
var driver = await Context
.Drivers
.Include(d => d.DriverStatusType)
.Where(d => d.DriverId == id)
.FirstOrDefaultAsync();

return driver;
}
}


Now when I call the GetDriverById(int id) method from my controller I get back what I'm expecting -



{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers":
}
}


However the GetAllDrivers() method is returning the nested drivers collection which means the data I'm getting back is huge -



[
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"displayText": "Tony Stark",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": [
{
"driverId": 2,
"surname": "Rogers",
"initials": "S",
"driverStatusTypeId": 2
},
{
"driverId": 3,
"surname": "Romanoff",
"initials": "N",
"driverStatusTypeId": 2
},
{
"driverId": 4,
"surname": "Banner",
"initials": "B",
"driverStatusTypeId": 2
},
...


I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?










share|improve this question























  • Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

    – Adam Vincent
    Nov 26 '18 at 12:34














4












4








4








I'm trying to load a related modal in Entity Framework Core but for some reason there's a nested collection being loaded when I haven't asked for it in my Include() call.



Here's my two models -



Driver.cs



public partial class Driver : IBaseEntity
{
public short DriverId { get; set; }
public string Surname { get; set; }
public string Initials { get; set; }
public byte DriverStatusTypeId { get; set; }

public DriverStatusType DriverStatusType { get; set; }
}


DriverStatusType.cs



public partial class DriverStatusType
{
public DriverStatusType()
{
Drivers = new HashSet<Driver>();
}

public byte DriverStatusTypeId { get; set; }
public string DriverStatusTypeName { get; set; }
public string Description { get; set; }

public ICollection<Driver> Drivers { get; set; }
}


DriversService.cs



public class DriverService : IDriverService
{
public DriverService(MyContext context)
{
Context = context;
}

public MyContext Context { get; }

public async Task<IEnumerable<Driver>> GetAllDrivers()
{
var drivers = await Context
.Drivers
.Include(d => d.DriverStatusType)
.toListAsync();

return drivers;
}

public async Task<Driver> GetDriverById(int id)
{
var driver = await Context
.Drivers
.Include(d => d.DriverStatusType)
.Where(d => d.DriverId == id)
.FirstOrDefaultAsync();

return driver;
}
}


Now when I call the GetDriverById(int id) method from my controller I get back what I'm expecting -



{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers":
}
}


However the GetAllDrivers() method is returning the nested drivers collection which means the data I'm getting back is huge -



[
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"displayText": "Tony Stark",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": [
{
"driverId": 2,
"surname": "Rogers",
"initials": "S",
"driverStatusTypeId": 2
},
{
"driverId": 3,
"surname": "Romanoff",
"initials": "N",
"driverStatusTypeId": 2
},
{
"driverId": 4,
"surname": "Banner",
"initials": "B",
"driverStatusTypeId": 2
},
...


I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?










share|improve this question














I'm trying to load a related modal in Entity Framework Core but for some reason there's a nested collection being loaded when I haven't asked for it in my Include() call.



Here's my two models -



Driver.cs



public partial class Driver : IBaseEntity
{
public short DriverId { get; set; }
public string Surname { get; set; }
public string Initials { get; set; }
public byte DriverStatusTypeId { get; set; }

public DriverStatusType DriverStatusType { get; set; }
}


DriverStatusType.cs



public partial class DriverStatusType
{
public DriverStatusType()
{
Drivers = new HashSet<Driver>();
}

public byte DriverStatusTypeId { get; set; }
public string DriverStatusTypeName { get; set; }
public string Description { get; set; }

public ICollection<Driver> Drivers { get; set; }
}


DriversService.cs



public class DriverService : IDriverService
{
public DriverService(MyContext context)
{
Context = context;
}

public MyContext Context { get; }

public async Task<IEnumerable<Driver>> GetAllDrivers()
{
var drivers = await Context
.Drivers
.Include(d => d.DriverStatusType)
.toListAsync();

return drivers;
}

public async Task<Driver> GetDriverById(int id)
{
var driver = await Context
.Drivers
.Include(d => d.DriverStatusType)
.Where(d => d.DriverId == id)
.FirstOrDefaultAsync();

return driver;
}
}


Now when I call the GetDriverById(int id) method from my controller I get back what I'm expecting -



{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers":
}
}


However the GetAllDrivers() method is returning the nested drivers collection which means the data I'm getting back is huge -



[
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"displayText": "Tony Stark",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": [
{
"driverId": 2,
"surname": "Rogers",
"initials": "S",
"driverStatusTypeId": 2
},
{
"driverId": 3,
"surname": "Romanoff",
"initials": "N",
"driverStatusTypeId": 2
},
{
"driverId": 4,
"surname": "Banner",
"initials": "B",
"driverStatusTypeId": 2
},
...


I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?







c# entity-framework-core






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 26 '18 at 9:36









Chris EdgingtonChris Edgington

1,18911224




1,18911224













  • Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

    – Adam Vincent
    Nov 26 '18 at 12:34



















  • Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

    – Adam Vincent
    Nov 26 '18 at 12:34

















Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

– Adam Vincent
Nov 26 '18 at 12:34





Are drivers already in memory from a previous call? What is the scope of your DbContext? What is the SQL query generated by EF for GetAllDrivers()

– Adam Vincent
Nov 26 '18 at 12:34












1 Answer
1






active

oldest

votes


















4















I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?




You are right, that's not the case. The idea of eager loading is to ensure the related data you specify is loaded. It doesn't mean/guarantee that related data won't be included.



It's partially explained in the Loading Related Data section of the EF Core documentation:




Tip



Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.




The navigation property fix-up means that anytime entity instance is materialized, all related navigation properties are updated to reflect it, for instance Driver is added to Driver.DriverStatusType.Drivers and vice versa.



Note that when using tracking queries, this might happen after the non including query is materialized (ToList()) because change tracker keeps track of object references and automatically updates them when you perform other tracking queries.



Another effect of that fix-up process is that when you include one of the ends of the relationship, the inverse navigation property of the other end is automatically populated.



So even if the first case the Drivers property should be populated and contain single item. And this is what actually happening in my clean tests, don't know why you are getting difference - may be the serializer is hiding it?



Anyway, all that means that you can't really control the content of the navigation properties. The only way you can control exactly what are you returning is to use special DTO/ViewModel etc. classes and projection (Select).






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478225%2fef-core-eager-loading-nested-collections%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4















    I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?




    You are right, that's not the case. The idea of eager loading is to ensure the related data you specify is loaded. It doesn't mean/guarantee that related data won't be included.



    It's partially explained in the Loading Related Data section of the EF Core documentation:




    Tip



    Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.




    The navigation property fix-up means that anytime entity instance is materialized, all related navigation properties are updated to reflect it, for instance Driver is added to Driver.DriverStatusType.Drivers and vice versa.



    Note that when using tracking queries, this might happen after the non including query is materialized (ToList()) because change tracker keeps track of object references and automatically updates them when you perform other tracking queries.



    Another effect of that fix-up process is that when you include one of the ends of the relationship, the inverse navigation property of the other end is automatically populated.



    So even if the first case the Drivers property should be populated and contain single item. And this is what actually happening in my clean tests, don't know why you are getting difference - may be the serializer is hiding it?



    Anyway, all that means that you can't really control the content of the navigation properties. The only way you can control exactly what are you returning is to use special DTO/ViewModel etc. classes and projection (Select).






    share|improve this answer




























      4















      I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?




      You are right, that's not the case. The idea of eager loading is to ensure the related data you specify is loaded. It doesn't mean/guarantee that related data won't be included.



      It's partially explained in the Loading Related Data section of the EF Core documentation:




      Tip



      Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.




      The navigation property fix-up means that anytime entity instance is materialized, all related navigation properties are updated to reflect it, for instance Driver is added to Driver.DriverStatusType.Drivers and vice versa.



      Note that when using tracking queries, this might happen after the non including query is materialized (ToList()) because change tracker keeps track of object references and automatically updates them when you perform other tracking queries.



      Another effect of that fix-up process is that when you include one of the ends of the relationship, the inverse navigation property of the other end is automatically populated.



      So even if the first case the Drivers property should be populated and contain single item. And this is what actually happening in my clean tests, don't know why you are getting difference - may be the serializer is hiding it?



      Anyway, all that means that you can't really control the content of the navigation properties. The only way you can control exactly what are you returning is to use special DTO/ViewModel etc. classes and projection (Select).






      share|improve this answer


























        4












        4








        4








        I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?




        You are right, that's not the case. The idea of eager loading is to ensure the related data you specify is loaded. It doesn't mean/guarantee that related data won't be included.



        It's partially explained in the Loading Related Data section of the EF Core documentation:




        Tip



        Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.




        The navigation property fix-up means that anytime entity instance is materialized, all related navigation properties are updated to reflect it, for instance Driver is added to Driver.DriverStatusType.Drivers and vice versa.



        Note that when using tracking queries, this might happen after the non including query is materialized (ToList()) because change tracker keeps track of object references and automatically updates them when you perform other tracking queries.



        Another effect of that fix-up process is that when you include one of the ends of the relationship, the inverse navigation property of the other end is automatically populated.



        So even if the first case the Drivers property should be populated and contain single item. And this is what actually happening in my clean tests, don't know why you are getting difference - may be the serializer is hiding it?



        Anyway, all that means that you can't really control the content of the navigation properties. The only way you can control exactly what are you returning is to use special DTO/ViewModel etc. classes and projection (Select).






        share|improve this answer














        I thought the idea of eager loading was to only include the related models you specify in the include statement but it seems this is not the case. Could someone explain what's happening here?




        You are right, that's not the case. The idea of eager loading is to ensure the related data you specify is loaded. It doesn't mean/guarantee that related data won't be included.



        It's partially explained in the Loading Related Data section of the EF Core documentation:




        Tip



        Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.




        The navigation property fix-up means that anytime entity instance is materialized, all related navigation properties are updated to reflect it, for instance Driver is added to Driver.DriverStatusType.Drivers and vice versa.



        Note that when using tracking queries, this might happen after the non including query is materialized (ToList()) because change tracker keeps track of object references and automatically updates them when you perform other tracking queries.



        Another effect of that fix-up process is that when you include one of the ends of the relationship, the inverse navigation property of the other end is automatically populated.



        So even if the first case the Drivers property should be populated and contain single item. And this is what actually happening in my clean tests, don't know why you are getting difference - may be the serializer is hiding it?



        Anyway, all that means that you can't really control the content of the navigation properties. The only way you can control exactly what are you returning is to use special DTO/ViewModel etc. classes and projection (Select).







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 26 '18 at 13:39









        Ivan StoevIvan Stoev

        103k774126




        103k774126
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478225%2fef-core-eager-loading-nested-collections%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

            Calculate evaluation metrics using cross_val_predict sklearn

            Insert data from modal to MySQL (multiple modal on website)