Search code examples
c#angularswaggerasp.net-core-webapiswagger-ui

Can't create a record with Swagger from C# class which has one-to-many relationship


I am trying to create booking type website, using ASP.NET Core API and Angular.

I got stuck on models / relations.

This is the Hotel model class:

public class Hotel
{
    [Key]
    public int HotelId { get; set; }

    // Hotel name
    [Column(TypeName = "nvarchar(50)")]
    public string HotelName { get; set; }

    [Range(1,5,ErrorMessage = "Hotel Star Rating Value Must be in between of 1 and 5.")]
    public byte Stars { get; set; }

    // Hotel address linked to Hotel class.
    public virtual ICollection<Address> HotelAddresses { get; set; }

    // Hotel rooms linked to hotel class.
    public virtual ICollection<Room> Rooms { get; set; }
}

This is the Address model class:

public class Address
{
    [Key]
    public int AddressId { get; set; }

    [Column(TypeName = "nvarchar(50)")]
    public string Country { get; set; }

    [Column(TypeName = "nvarchar(50)")]
    public string City { get; set; }

    [Column(TypeName = "nvarchar(50)")]
    public string Street { get; set; }

    // one-to-many.
    [ForeignKey("hotel")]
    public int HotelId { get; set; }
    public virtual Hotel hotel { get; set; }
}

This is the Room model class:

public class Room
{
    [Key]
    public int RoomId { get; set; }

    [Column(TypeName ="nvarchar(50)")]
    public string Name { get; set; }

    [Column(TypeName = "nvarchar(250)")]
    public string Description { get; set; }

    public decimal price { get; set; }

    // one-to-many
    [ForeignKey("hotel")]
    public int HotelId { get; set; }
    public virtual Hotel hotel { get; set; }
}

Controller action method:

[HttpPost]
public async Task<ActionResult<Hotel>> PostHotel(Hotel hotel)
{
    _context.Hotels.Add(hotel);
    await _context.SaveChangesAsync();

    return CreatedAtAction("GetHotel", new { id = hotel.HotelId }, hotel);
}

So the question is: what Am I doing wrong?

If nothing how am I supposed to create a record manually while I'm trying to have foreign keys and stuff?

SwaggerUI

I tried creating one-to-many relationship differently, lots of times, I thought it was about my code which was wrong and I thought by fixing my model classes Swagger UI would make it easier to create new record (to do post method basically) but I get confused when Swagger gives me format which considers me to write Hotel model and Ids too like aren't they supposed to be automated?


Solution

  • This is one of the reasons why you might prefer to use DTOs instead of your entity classes as input/output for you APIs. In this particular case you basically have a cyclic relationship between Hotel and Address which breaks not only swagger but will require to jump some hoops (if it is even possible) to post such model. As a quick fix you can make the hotel part of relationship optional (which is not ideal from EF Core design point of view):

    public class Adress
    {
        // ...
        [JsonIgnore]
        public virtual Hotel? Hotel { get; set; }    
    }
    

    But I would highly recommend to create a separate set of objects. Like for example:

    public class CreateHotelRequest
    {
        public required string HotelName { get; set; }
        [Range(1,5,ErrorMessage = "Hotel Star Rating Value Must be in between of 1 and 5.")]
        public required byte Stars { get; set; }
    
        public virtual ICollection<AddressDto> HotelAdresses { get; set; }
        public virtual ICollection<RoomDto> Rooms { get; set; }
    }
    

    And for example AddressDto:

    public class AddressDto
    {
        public required string Country { get; set; }
    
        public required string City { get; set; }
    
        public required string Street { get; set; }
    }