2

I'm having a really tough time finding guidance on how to AVOID including navigation properties in EF Core in a database-first approach. Using unmodified scaffolded web API controllers in Visual Studio, I have an entity that looks like this (simplified for example):

public partial class ProjectPhase
{
  public ProjectPhase()
  {
     Projects = new HashSet<Project>();
  }

  public int PhaseId { get; set; }
  public string PhaseName { get; set; }

  public virtual ICollection<Project> Projects { get; set; }
}

My request is the default scaffolded HTTP GET request:

// GET: api/Phases
[HttpGet]
public async Task<ActionResult<IEnumerable<ProjectPhase>>> GetPhases ()
{
  return await _context.ProjectPhases.ToListAsync();
}

The return value looks like this:

...{
  "phaseId": 1,
  "phaseName": "Pilot",
  "projects": []
},...

I want this request to NOT include projects in the returned object. How do I do this?

madreflection
  • 4,744
  • 3
  • 19
  • 29
TheDoc
  • 688
  • 2
  • 14
  • 33
  • https://stackoverflow.com/questions/10169648/how-to-exclude-property-from-json-serialization#:~:text=If%20you%20are%20using%20Json,property%20while%20serializing%20or%20deserialising.&text=Or%20you%20can%20use%20DataContract,serialize%2Fdeserialize%20properties%2Ffields. – Michael Jun 11 '20 at 18:59
  • 5
    I would create a DTO for that response and don't include that property. That way you will control what will be returned to the client. – devcrp Jun 11 '20 at 18:59
  • Yeah, @devcrp suggestion is better – Michael Jun 11 '20 at 19:00
  • @devcrp so you're saying for every entity, I should make a `DTO` type that doesn't include that `projects` property. Then all the default requests need to be changed to something like, `_context.ProjectPhases.Select(p => new DTO { PhaseId = p.PhaseId, PhaseName = p.PhaseName }).ToListAsync()`, right? I've done this up until now, but I wind up having to make tons of new types to handle all my db models. I was looking for a shortcut. Is there not a simpler way? EDIT: The reason is, all my DTOs are just the object properties without the virtual ones...nothing complex – TheDoc Jun 11 '20 at 19:06
  • @TheDoc maybe this helps? https://stackoverflow.com/questions/11320968/can-newtonsoft-json-net-skip-serializing-empty-lists – devcrp Jun 11 '20 at 19:14
  • Navigation properties are not included, you don't get any values in it only if you are specific about it, so one thing is to refine your Dto or partial Model and another is what you are asking, entity framework does not include if there's not projection of the navigation. – SilentTremor Jun 11 '20 at 19:14

2 Answers2

2

if you want to read-only an entity use AsNoTracking.

The AsNoTracking() extension method returns a new query and the returned entities will not be cached by the context (DbContext or Object Context).

[HttpGet]
public async Task<ActionResult<IEnumerable<ProjectPhase>>> GetPhases()
{
  return await _context.ProjectPhases.AsNoTracking().ToListAsync();
}

And another way to make the final object better by using a DTO class that matches the entity class and use automapper maybe for mapping.

Ali Kleit
  • 3,069
  • 2
  • 23
  • 39
2

For my purposes, using something like Automapper was a bit overkill. I just wanted to exclude a few navigation properties, so I just used the JsonIgnore attribute like so.

public int PhaseId { get; set; }
public string PhaseName { get; set; }

[System.Text.Json.Serialization.JsonIgnore]
public virtual ICollection<Project> Projects { get; set; }

Hope this helps someone else!

TheDoc
  • 688
  • 2
  • 14
  • 33