locked
Problems Disabling Lazy Loading in Asp.net core RRS feed

  • Question

  • User1984354752 posted

    Hi there:

    I have the latest asp.net core version ( 5.0.1) in my project and want to disable  the Lazyloading so I can proceed with the eager loading of the entities I want via Configuration.LazyLoadingEnabled = false;   in my dBContext according to this link: Avoid Lazy Loading Entities in ASP.NET Applications | Blog (ardalis.com).

    The first problem that I encounter is the compiler doesn't pick up the Configuration in the dbContext.  I added the using System.Configuration; in the dbContext which brings the Configuration class but it doesn't have  the lazyloadingEnabled property which means that this isn't the right class. I searched and found this link Lazy Loading of Related Data - EF Core | Microsoft Docs that hints that I should install the Proxies package which I did. Now the problem is that the package plays havoc with the previous relationships to the extend that I ended up deleting the proxies package as I'm not sure if this is the right way.

    Can someone assist me which is the right way please?

    Thanks in advance. 

    Sunday, January 10, 2021 4:59 PM

All replies

  • User475983607 posted

    you've posted in a .NET Core forum.  Lazy loading is disabled by default in EF Core.   You actually have to write configuration to enable lazy loading.

    https://docs.microsoft.com/en-us/ef/core/querying/related-data/lazy

    Also, your blog link is for EF 6 not EF Core.  Is this an EF 6 question?

    Sunday, January 10, 2021 5:19 PM
  • User1984354752 posted

    Hi Mgebhard:

    This is a EF Core question. sorry for posting in the wrong forum. Further to your explanation, I found this article https://csharp.christiannagel.com/2019/01/30/lazyloading/  which confuses me more . I read in the article that since  EF Core  version 2.1 lazy loading  is  available by  accessing the property dynamically which  invokes a query to the database to retrieve the data for the needed references.

    I run the code below and effectively EF core is doing the lazy loading which, according to the article,  is very different to lazy loading with Entity Framework 6.

    IQuerable<ContractViewModel>query=_UoW.Repository<Contracts>().Getlist().Select(f=>new ContractViewModel {

    Project=f.ProjectNavigation.Project,

    Company =f.IdCompanyNavigation.Companyname

    }

    Having said this. my question remains ..how I disabled LAZY LOADING  option in EF CORE ?

    Monday, January 11, 2021 1:11 PM
  • User475983607 posted

    As explained in my first thread, in EF Core lazy loading is off by default.  You have to add configuration to enable lazy loading in EF Core.   This information is openly and clearly published in the linked documentation from my first post. 

    https://docs.microsoft.com/en-us/ef/core/querying/related-data/lazy

    This information is also your most recent post for Core 2.1.  

    From your linked post...

    Because of the disadvantages of lazy loading, comparing the implementations of lazy loading between Entity Framework and EF Core, it’s now implemented in a different way. You need to explicitly turn it on.

    It seems you did not read the entire link?

    Having said this. my question remains ..how I disabled LAZY LOADING  option in EF CORE ?

    Did you enable lazy loading and now you want to remove lazy loading?  If so, Just remove the configuration you setup when you enabled lazy loading.  

    Monday, January 11, 2021 1:46 PM
  • User1984354752 posted

    Hi Mgebhard:

    I did not enable lazy loading. I did the following in order to be sure:

    1) checked in the project solution packages folders for Microsoft.EntityFrameworkCore.Proxies package.........nothing 

    2)  Checked in the NugGet solution in the installed tab for Microsoft.EntityFrameworkCore.Proxies package....nothing 

    3) Checked thoroughly in the DbContext and Startup classes for a configuration referring to lazy loading .....nothing 

    4) Lastly I searched in the Solution explorer any word referring to lazy loading, Proxies, etc ......nothing pop ups 

    Still when I run my code, EF Core lazy loads the related data via the navigation properties.  I'm not eagerly  including any data in the query ..it's EF Core lazy loading though I haven't configured anything being the reason why I initially posted the question. Don't know if I'm missing something that is just right in front of my nose .

    Any hint please?

    Monday, January 11, 2021 3:05 PM
  • User475983607 posted

    Still when I run my code, EF Core lazy loads the related data via the navigation properties.  I'm not eagerly  including any data in the query ..it's EF Core lazy loading though I haven't configured anything being the reason why I initially posted the question. Don't know if I'm missing something that is just right in front of my nose .

    Any hint please?

    Share sample code the community can easily run to reproduce this problem.  

    Monday, January 11, 2021 3:18 PM
  • User753101303 posted

    Hi,

    More likely you are mistakenly using EF 6.3 which is compatible with .NET Core (intended rather to ease porting) and for which lazy loading is enabled by default.

    Check if you are using  https://www.nuget.org/packages/EntityFramework/ or https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.

    If confirmed and this is a new application, you should likely uninstall EF 6.x and install EF Core instead.

    Monday, January 11, 2021 7:51 PM
  • User1984354752 posted

    Hi Patrice:

    Nuget Package Manager confirms that neither Entity Framework 6  nor Entity Framework Core is installed in the project.. I browsed both packages and VS is saying they aren't installed. 

    What is installed in the Framework folders  are MicrosoftApsNetCore.App and Microsoft.NetCoreApp and in the Package folders there are lot of packages e.j Jquery, Automapper, System.Linq.Async, and a  lot of Microsoft.AspNetCore pacjages such as Identity, Sql server, Tools, etc.

    My limited knowledge cannot help me to discern which Framewaork I have been using. I'm half way in the development ....does the installation of EF Core framework would affect the work done thus far?

    Thanking you in advance.

    Kind regards  

    Thursday, January 14, 2021 11:36 AM
  • User753101303 posted

    Can you give the namespace of the DbContext class you are using? If unsure try for example

                var str = typeof(DbContext).FullName;
                System.Diagnostics.Debug.WriteLine(str);

    and  use the debugger or the output window to see which value you have.

    If Microsoft.EntityFrameworkCore.DbContext you are using EF Core
    If System.Data.Entity.DbContext you are using likely EF 6.x (or possibyl an older version?)

    Thursday, January 14, 2021 12:05 PM
  • User475983607 posted

    Better yet can you share an example of lazy loading?

    Thursday, January 14, 2021 12:26 PM
  • User1984354752 posted

    Hi Patrice:

    I hove over the DBContent class and shows that is coming from Microsoft.EntityFrameworkCore which means that I'm using EF Core as I suspected.

    Yet. I'm still uncertain about the following:

    How it come that the Nuget Package Manager is saying that the Frameworkcore isn't installed when I browse it ? My quess is that by installing Microsoft.AspnetCore packages I indirectly installed the framework ???

    Now knowing that we have the  EF Core, the initial question still remains why the lazy loading is performed. I'm putting again the code in full so you can see whether I'm missing something here .

     public  class GenericRRepository<T> : IGenericRepository<T> where T : class
        {
            protected HousingContext _context;

            
            private readonly IUnitOfWorkAsync _unitOfWork;

            public GenericRRepository(HousingContext context)
            {
                _context = context;

                _unitOfWork = new UnitOfWorkAsc(context);
                
            }

      public IQueryable<T> Getlist(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "", int? page = null,
                int? pageSize = null)
            {
                IQueryable<T> query = _context.Set<T>();
                if (filter != null)
                {
                    query = query.Where(filter);
                }

                if (orderBy != null)
                {
                    query = orderBy(query);
                }

                if (includeProperties != null)
                {
                    foreach (
                        var includeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        query = query.Include(includeProperty);
                    }
                }

                if (page != null && pageSize != null)
                {
                    query = query.Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value);
                }

                return  query.AsQueryable();
            }

    }

    Controller

    public async Task<IActionResult> Index(, int? Id = null)
            {

     IQueryable<ContractViewModel> query = _UoW.Repository<Contracts>().Getlist().Select(f => new ContractViewModel
                {
                    Project = f.ProjectNavigation.Project,
                    Company = f.IdCompanyNavigation.Companyname,
                    Office=f.ProjectNavigation.DistrictOfficeNavigation.Office,
                    Project_Manager=f.ProjectNavigation.AssignedProjectManagerNavigation.Fullname,
                    Id = f.Id,
                    Value = f.ContractValue,
                    Contigencies = f.Contigencies,
                    Total_Contract_Value = f.Total,
                                 
                    Contractual_Committment = f.ContractAmounts.Sum(y => y.ContractBreakdownAmount) ?? 0,              
                    Expenditure_to_Date =(decimal)f.ContractAmounts.SelectMany(k=>k.Invoices).Sum(p=>p.TotalCostToEmployer),
                    

                    Description = f.Contractdescription
                });

    }

    1) Getlist method doesn't call the include property hence I'm not doing eager loading.  when the code runs EF core load all the related data referred in the navigation properties ...according to Microsoft documentation this happens when this option is enabled which isn't the case as I checked   thoroughly  already. 

    In short, knowing that EF core is installed and the lazy loading option hasn't been activated, all together gives me the impression that there is something missing  that could explain why the Nuget Package Manager dosen't recognized the EF core in  its browse as an installed package ...

    Any hint from you ? 

    Thursday, January 14, 2021 3:39 PM
  • User1984354752 posted

    Hi Mgebhard

    I provided the code when I respond to Patrice ......any quess? 

    Thursday, January 14, 2021 3:42 PM
  • User475983607 posted

    I provided the code when I respond to Patrice ......any quess?

    You misunderstand how your code works.  IQueryable<T> is like a potential query.   Your code is designed to programmatically build a query.   Then eventually execute the query.  You did not shared the code that executes the query.  

    Thursday, January 14, 2021 4:54 PM
  • User1984354752 posted

    HI Mgebhard:

    Here is the ode that executes the query 

    return View(await PagingList<ContractViewModel>.CreateAsync(query, pageNumber ?? 1, pageSize));

      public class PagingList<T> : List<T>
        {

       public static async Task<PagingList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
            {
                var count = await source.CountAsync();
                var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
                return new PagingList<T>(items, count, pageIndex, pageSize);
            }

    }

    I don't understand how  the  execute the query impacts in the loading of related data ???. The  query that returns my IQuerable<T> comes from  the Gelist  method from a Generic Repository which checks whether the include property is null or not to include the related data via eager loading......in this case I'm telling my GenericRepository to execute a query without eager loading. so even if I include the navigation properties EF core isn't supposed to load the related data as I haven't activated the lazy loading option. 

    Have to take a look at the Getlist method? I'm reposting again below 

    public IQueryable<T> Getlist(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "", int? page = null,
                int? pageSize = null)
            {
                IQueryable<T> query = _context.Set<T>();
                if (filter != null)
                {
                    query = query.Where(filter);
                }

                if (orderBy != null)
                {
                    query = orderBy(query);
                }

                if (includeProperties != null)==> it's here where I tell to EFcore to load eagerly the related data .....in our case I'm  telling to do  it ...neither the lazy loading option is activated so why is loading the data ????
                {
                    foreach (
                        var includeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        query = query.Include(includeProperty);
                    }
                }

                if (page != null && pageSize != null)
                {
                    query = query.Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value);
                }

                return  query.AsQueryable();
            }

    Thursday, January 14, 2021 5:40 PM
  • User475983607 posted

    Lazy loading occurs when a property of an entity is accessed and the framework does a query to populate the property.  The code you've shown prepares a query to execute.  You have not shared any code that lazy loads an entity property or properties at a later time.

    Thursday, January 14, 2021 8:00 PM
  • User1984354752 posted

    Mgebhard:

    It seems you haven't read the post from the top to the bottom: I

    I know what is lazy loading and how to access this.  Again I will trey to recap for you;

    1) The code that lazy load an entity property was above posted, but I will do it again f

    Iquerable<ContractViewModel>query=_UOW.Repository<Contracts>().Getlist().Select (f=>new ContracViewModel

    {
    Project=f.ProjectNavigation.Project,

    company =f.IdCompanyNavigation.Compayname.

    }

    As you know in EF 6 lazy loading is by default on, but I'm using EF Core and haven't configured my project to enable Lazy loading hence even if I explicitly coded the above  entity property to use Lazy loading, EF Core isn't supposed to load any data as, again, this option isn't enabled....this is what understood from reading Microsoft documentation. When I run the code EF core loads the related data anyway as the lazy loading  is on when in fact isn't not.

    Other possibility could be if I'm  doing eager loading. If you look at the code above, I explained that the Getlist() procedure has a property named : included properties where I explicitly  tell to EF Core to include the entities I want. As you can see I'm  not declaring any eager loading either .

    In a nutshell, Yes there is a lazy loading declaration but EF CORE isn't supposed to load the data as the option isn't on and I'm not including properties in the query ( eager loading) .

    Can you tell me  the wrongs now ?

    Regards.

    Friday, January 15, 2021 1:31 PM
  • User475983607 posted

    9peculiar

    Can you tell me  the wrongs now ?

    You misunderstand lazy loading and IQuerable<T>.  The code below came from this site's tutorials (Getting Started with Razor Pages tutorial) which illustrates how IQueryable<T> works.  You can see how the IQuerable<T> object below is being build until finally at the end, the query is invoked which populates the entity.  The only difference between your code and the Getting Starting code below is your query is a projection.  See my second example below which illustrates the concept(s) you are struggling with.

    public async Task OnGetAsync(string sortOrder,
        string currentFilter, string searchString, int? pageIndex)
    {
        CurrentSort = sortOrder;
        NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
        DateSort = sortOrder == "Date" ? "date_desc" : "Date";
        if (searchString != null)
        {
            pageIndex = 1;
        }
        else
        {
            searchString = currentFilter;
        }
    
        CurrentFilter = searchString;
    
        IQueryable<Student> studentsIQ = from s in _context.Students
                                            select s;
        if (!String.IsNullOrEmpty(searchString))
        {
            studentsIQ = studentsIQ.Where(s => s.LastName.Contains(searchString)
                                    || s.FirstMidName.Contains(searchString));
        }
        switch (sortOrder)
        {
            case "name_desc":
                studentsIQ = studentsIQ.OrderByDescending(s => s.LastName);
                break;
            case "Date":
                studentsIQ = studentsIQ.OrderBy(s => s.EnrollmentDate);
                break;
            case "date_desc":
                studentsIQ = studentsIQ.OrderByDescending(s => s.EnrollmentDate);
                break;
            default:
                studentsIQ = studentsIQ.OrderBy(s => s.LastName);
                break;
        }
    
        int pageSize = 3;
        Students = await PaginatedList<Student>.CreateAsync(
            studentsIQ.AsNoTracking(), pageIndex ?? 1, pageSize);
    }

    You're making the argument the pattern below is lazy loading which is not true.  The pattern is another way to include a navigation property using a select.

                //Add Enrollments
                var query = studentsIQ.Select(f => f.Enrollments);
                //Execute the query
                var results = query.ToList();

    Friday, January 15, 2021 4:04 PM