I am building out a demo for an API in .NET Core and constructing a nested JSON object that needs to get constructed through a series of LINQ queries.
My current issue is that when i get about 4 layers deep, I want to customize what actually gets serialized, more specifically, i want to "Not Include" specific navigation properties for this query specifically, but not for general purpose, only for this specific query.
My first thought was to do a DTO, but that seems like an unnecessary extra model just for this one specific case...i'd like to work with LINQ directly to manipulate for my result.
I have already added the following to my Startup.cs file to avoid cycles:
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
I have 5 models currently in action that look like this:
public class Hotel
{
public int ID { get; set; }
public string Name { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Phone { get; set; }
public List<HotelRooms> HotelRooms { get; set; }
}
public class Room
{
public int ID { get; set; }
public string Name { get; set; }
public Layout Layout { get; set; }
public List<RoomAmenities> RoomAmenities { get; set; }
public List<HotelRooms> HotelRooms { get; set; }
}
public class HotelRooms
{
public int HotelID { get; set; }
public int RoomNumber { get; set; }
public int RoomID { get; set; }
public decimal Rate { get; set; }
public bool PetFriendly { get; set; }
public Hotel Hotel { get; set; }
public Room Room { get; set; }
}
public class Amenities
{
public int ID { get; set; }
public string Name { get; set; }
// Navigation Properties
public List<RoomAmenities> RoomAmenities { get; set; }
}
public class RoomAmenities
{
public int RoomID { get; set; }
public int AmenitiesID { get; set; }
public Room Room { get; set; }
public Amenities Amenity { get; set; }
}
In my services, i have this logic that is actually doing the querying:
public async Task<Hotel> GetById(int id)
{
var hotel = await _context.Hotel.FindAsync(id);
// Get a list of rooms
var rooms = await _context.HotelRooms.Where(r => r.HotelID == id)
.Include(d => d.Room)
.ThenInclude(a => a.RoomAmenities)
.ThenInclude(x => x.Amenity).ToListAsync();
hotel.HotelRooms = rooms;
return hotel;
}
The current output is:
{
"id": 1,
"name": "Amanda's Hotel",
"streetAddress": "123 CandyCane Lane",
"city": "Seattle",
"state": "WA",
"phone": "123-456-8798",
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75.00,
"petFriendly": false,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker",
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar",
"roomAmenities": []
}
}
],
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120.00,
"petFriendly": true
}
]
}
}
]
}
}
],
"hotelRooms": []
}
},
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120.00,
"petFriendly": true,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker",
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [],
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75.00,
"petFriendly": false
}
]
}
}
]
}
},
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar",
"roomAmenities": []
}
}
],
"hotelRooms": []
}
}
]
}
This is much too nested for me, i'd like the inner "roomAmenities" inside the "amenity" object to not be included. I'd like my object to look like this:
{
"id": 1,
"name": "Amanda's Hotel",
"streetAddress": "123 CandyCane Lane",
"city": "Seattle",
"state": "WA",
"phone": "123-456-8798",
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75,
"petFriendly": false,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker"
}
}
],
"hotelRooms": []
}
},
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120,
"petFriendly": true,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker"
}
},
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar"
}
}
],
"hotelRooms": []
}
}
]
}
Does anyone have any guidance on how i can achieve this with EFCore and LINQ?