9

I have two classes:

  • Campaign which references a class customer:

    public class Campaign
    {
        [Key]
        [Required]
        public int id { get; set; }
        public int? CustomerId { get; set; }
        [ForeignKey("CustomerId")]
        public virtual Customer customer { get; set; }
    }
    
  • And Customer:

    public class Customer
    {
        [Key]
        [Required]
        public int id { get; set; }
        [Required]
        public string name { get; set; }
        [Required]
        public double turnover { get; set; }
        public virtual ICollection<Campaign> campaigns { get; set; }
    }
    

Here's is an insert method:

async Task<Campaign> ICampaignRepository.InsertCampaign(Campaign campaign)
{
    try
    {
        _context.Campaigns.Add(campaign);
        await _context.SaveChangesAsync();
        return campaign;
    }
    catch (Exception)
    {
        throw;
    }
}

I'm using Microsoft.EntityFrameworkCore.Proxies package for lazy loading.

After adding a campaign instance having a customerId, the customer is not lazy loaded in the inserted object. Please note that I tried to fetch the campaign by id before returning it, but the problem persists, and I want to avoid loading the customer explicitly.

Lazy loading is perfectly working when performing fetch operations on existing records.

6
  • EF Core isn’t lazy loading anything by default (that’s a good thing btw.), and I don’t think automatically loading related things on added entities is supported at all. Commented Jul 24, 2019 at 10:47
  • I'm using Microsoft.EntityFrameworkCore.Proxies package for lazy loading Commented Jul 24, 2019 at 11:00
  • The entity you get passed to your function very likely isn’t a proxy entity though. So the lazy loading magic won’t happen there. You might need to create the object with _context.CreateProxy(). Commented Jul 24, 2019 at 11:07
  • _context.CreateProxy() should be called to create the parent object or the navigation property ? Commented Jul 24, 2019 at 11:14
  • The Campaign object that you are adding to the context. Commented Jul 24, 2019 at 11:20

1 Answer 1

12

Thanks to poke

The solution is to:

  1. Create a proxy for your entity using CreateProxy:

    Campaign toCreate = _context.Campaigns.CreateProxy();
    
  2. Transfer new values to your proxy object:

    _context.Entry(toCreate).CurrentValues.SetValues(Campaign);
    
  3. Finally, save your proxy object to the context:

    _context.Add(toCreate);
    await _context.SaveChangesAsync();`
    

Here's the full method:

async Task<Campaign> ICampaignRepository.InsertCampaign(Campaign campaign)
{
    Campaign toCreate = _context.Campaigns.CreateProxy();
    _context.Entry(toCreate).CurrentValues.SetValues(campaign);
    _context.Add(toCreate);
    await _context.SaveChangesAsync();
    return toCreate;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Just a heads up for anyone trying this, if Campaign in your case contains collections you may wanna double check if _context.Entry(toCreate).CurrentValues.SetValues(campaign) actually assigns the collections. In my case it silently didn't, could be because I am on an older version (EF Core 3.1.32) or something local, not sure. But I used a mapper (AutoMapper in my case) to do the assignment of values from the object to the proxy. Something like: Campaign toCreate = _context.Campaigns.CreateProxy(); _context.Add(toCreate); Mapper.Map(campaign, toCreate);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.