Vy Do
Vy Do

Reputation: 52488

How to enable lazy loading in Entity Framework Core 7.0.2 (.NET 7.0.2)?

My environment: Windows 11 x64, .NET 7.0.2 , ASP.NET Core WebAPI 7.0.2 , Visual Studio 2022 Community edition, Microsoft SQL Server 2014 Express edition.

I install NuGet package, in csproj has

<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.2" />

My try

    public virtual DbSet<VoucherTypeCategory> VoucherTypeCategories { get; set; }

    public virtual DbSet<VoucherTypeCategoryRefType> VoucherTypeCategoryRefTypes { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
        .UseLazyLoadingProxies()
        .UseSqlServer("Server=.\\***********;Database=***********SampleVy;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.ApplyConfiguration(new RoleConfiguration());
        //modelBuilder.ApplyConfiguration(new CountryConfiguration());
        //modelBuilder.ApplyConfiguration(new HotelConfiguration());

        modelBuilder.Entity<Account>(entity =>
        {
            entity.HasKey(e => new { e.AccountId, e.AccountNumber });

enter image description here (Please focus at these text ...Navigations": [] https://gist.github.com/donhuvy/1cc7f3d8a854ca803c5195ba6b3a93b8 )

As you seen, I have

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
        .UseLazyLoadingProxies()
        .UseSqlServer("Server=.\\***********;Database=***********SampleVy;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true");

but lazy loading still not work, Please guide me make lazy load work. How to enable lazy loading in Entity Framework Core 7.0.2 (.NET 7.0.2)?

Update 1: Maybe I used incorrect words, my ultimate purpose is don't loading so much data (1.95 MB JSON), I need data in one table only (few KB JSON).

Update 2: Use .AsNoTracking()

using acc.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Data;

namespace acc.Controllers
{
    // Chart of accounts.
    [Route("api/[controller]")]
    [ApiController]
    public class AccountTreeController : ControllerBase
    {
        private readonly ILogger<AccountTreeController> _logger;
        private readonly Acc200Context _db;

        public AccountTreeController(ILogger<AccountTreeController> logger, Acc200Context acc200Context)
        {
            _logger = logger;
            _db = acc200Context;
        }

        // Get list of accounts of an tenant. For account tree.
        [HttpGet("{tenant_id}/all/")]
        [Authorize(Roles = "User")]
        // [Authorize]
        public IEnumerable<Account> Get(Guid tenant_id)
        {
            // return _db.Accounts.Where(x => x.TenantId == tenant_id).ToArray();
            return _db.Accounts
                .AsNoTracking()
                .ToList();
        }

Error (message in Postman)

{
    "ErrorType": "Failure",
    "ErrorMessage": "An error was generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning': An attempt was made to lazy-load navigation 'AccountDefaults' on a detached entity of type 'AccountProxy'. Lazy loading is not supported for detached entities or entities that are loaded with 'AsNoTracking'. This exception can be suppressed or logged by passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'."
}

Update 3 Add .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)

builder.Services.AddDbContext<Acc200Context>(options => options.UseSqlServer("Server=.\\************;Database=************;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true")

.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
);

Postman message

{
    "ErrorType": "Failure",
    "ErrorMessage": "An error was generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning': An attempt was made to lazy-load navigation 'AccountDefaults' on a detached entity of type 'AccountProxy'. Lazy loading is not supported for detached entities or entities that are loaded with 'AsNoTracking'. This exception can be suppressed or logged by passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'."
}

Upvotes: 2

Views: 2352

Answers (1)

Kailash
Kailash

Reputation: 550

The concept of lazy loading implies that the entity (or other data) is loaded when it is actually referenced/used. So, if you were running through a loop within an app and only referenced the parent entity, the child entity would not get loaded. However, if you refence and use the child entity, at that point it would get loaded.

If you expose an entity with sub entities through an API, the Web API/MVC serializer automatically references/uses all fields within the entity including the child entity during serialization of the response model as part result conversion. In this case, it would return all data including the child fields which are lazy loaded based on your setup.

If you really want to return part of the data, you have multiple options including:

  • Intermediate mapping: Decouple response model from entity and use include/expand query parameter to decide whether to map the child entity. In this case you will respond back with a different object (not the entity) but another object with a same set of fields. Then based on the query parameter passed in you will either only map the base fields vs all fields from entity to response object. So, if the expand/include parameter is false, only map base fields and since the serializer is not acting on the entity (acts on separate response model) which will give you the partial response you are looking for.
  • Pagination: This instead of lazy loading sub objects, helps you load part of the collection and then page through it. This medium post does a good job of explaining pagination. https://ignaciochiazzo.medium.com/paginating-requests-in-apis-d4883d4c1c4c

Upvotes: 1

Related Questions