Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push queries on lazy navigation properties to database (a.k.a extra lazy loading) #1204

Open
Tracked by #22954
NotMyself opened this issue Dec 2, 2014 · 9 comments

Comments

@NotMyself
Copy link

Hi Team,

I am a former NHibernate user that is switching over to using Entity Framework. I wanted to share with you a scenario that surprised me when I first encountered it. You can see my write up and sample code here. The full source of the project is located here.

TLDR: My Account entity has a Transactions collection. Attempting to pull data out of the transactions collection loads all the transactions from the database, even though I have constrained all transaction access in the model to limit the number of them coming back.

You all may not even be focus on this right now, but it's a use case that is needed. Keep it in your back pocket. 👍

@rowanmiller rowanmiller changed the title Lazy collection properties not respecting queries Push queries on lazy navigation properties to database Dec 5, 2014
@rowanmiller rowanmiller added this to the Backlog milestone Dec 5, 2014
@rowanmiller
Copy link
Contributor

We agree this would be a good thing to enable.

@NotMyself
Copy link
Author

That's what we like to hear...

@divega divega changed the title Push queries on lazy navigation properties to database Push queries on lazy navigation properties to database a.k.a extra lazy loading Aug 8, 2016
@divega divega changed the title Push queries on lazy navigation properties to database a.k.a extra lazy loading Push queries on lazy navigation properties to database (a.k.a extra lazy loading) Aug 8, 2016
@joelmdev
Copy link

I'm a surprised this doesn't get more requests/attention- possibly another duplicate issue somewhere in github? There are questions in other forums of this same nature going back several years. I've had to find workarounds for this very problem more than a couple of times, and they usually result in robbing an Entity of functionality in order to avoid loading a large collection of related Entities. Would love to see this added.

@Cooksauce
Copy link

Cooksauce commented Aug 10, 2019

Have there been any decisions/discussions around this? What are the team's current thoughts? My use case revolves heavily around entities with navigation properties containing 10k - 500k items.

In this scenario, it would be much cleaner to give EF a property or method to override than having DbContext.Entry() calls everywhere.

Wrapping that in an extension is an option:
IQueryable<Employee> employeeQuery = department.CollectionQuery(x => x.Employees, dbcontext);

... but that's not as nice as something like:
IQueryable<Employee> employeeQuery = department.NavigationQuery(x => x.Employees);

... or even further:
IQueryable<Employee> employeeQuery = department.EmployeesQuery;

Defining The Entity
From an entity definition perspective, you could give EF a method/property to override. This could look like:

public class Department
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string SomeOtherData { get; set; }

    public virtual IList<Employee> Employees { get; set; }
    
    // This could be nice since it could function to access the querys for every navigation property. You could also move this into a base 'Entity' class and have everything inherit from that.
    public virtual IQueryable<TNavigation> NavigationQuery<TNavigation>(Expression<Func<Department, TNavigation>> selector) => Employees.AsQueryable();
}

public class Employee
{
    public int Id { get; set; }

    public int DisplayOrder { get; set; }

    public int DepartmentId { get; set; }

    public virtual Department Department { get; set; }
}

OR

public class Department
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string SomeOtherData { get; set; }

    public virtual IList<Employee> Employees { get; set; }

    // Notice getter only to since this would reference the underlying Employees list above
    public virtual IQueryable<Employee> EmployeesQuery { get; }
}

public class Employee
{
    public int Id { get; set; }

    public int DisplayOrder { get; set; }

    public int DepartmentId { get; set; }

    public virtual Department Department { get; set; }
}

// Could be set through the fluent api via:
builder.Entity<Department>().Property(x => x.Employees).HasQuery(x => x.EmployeesQuery);

What are everyone's thoughts? How else can EF effectively abstract a large navigation property? All of the current workarounds inhibit EF's ability to allow consumers to interact with these properties as if they were in memory.

Couldn't these all simply be implemented as wrappers around the EntityEntry<>.Collection().Query() method? @ajcvickers

@ajcvickers
Copy link
Contributor

@Cooksauce I think we would want to do this without requiring the use of dynamic proxies. The implementation probably isn't too different from regular lazy loading in that respect.

@Cooksauce
Copy link

@ajcvickers What are the team's thoughts on implementing this? This issue is over 4 years old, have there been any recent discussions about it?

@ajcvickers
Copy link
Contributor

@Cooksauce It's not high on our priority list, and the issue only has one vote, so I don't expect it's something we will get to any time soon.

@jimmyp
Copy link

jimmyp commented Jan 10, 2020

It would be really great to see this implemented. I have exactly the same issue

@LucStr
Copy link

LucStr commented Aug 25, 2021

Is there an update to this?
Personally I think it would be great if EF would keep it's current implementation as is, but if the Navigation Property is of Type IQueryable, it would automatically wrap the code in

_dbContext
                .Entry(entity)
                .Collection(x => x.Collection)
                .Query()

instead of throwing an InvalidOperationException

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants