Search code examples
c#.net.net-core

.NET Core DB vs JSON model design


I'm designing an API with a set of relatively straight-forward models and relationships. Lots of the documentation and examples I can find seem to suggest designing a single model that acts both as the DB model and the JSON model. At first this seemed ideal to reduce the volume of code. However with a simple relationship there seems to be difficulties having a single model cover the needs of both the DB model and the JSON model. And I'm not against duplicating, but that seems to result in repetitive field-copying where I'm sure there's a better way.

Consider a table of tracks that each contains a list of track points.

public class Track
{
   [Key]
   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public long Id { get; set; }

   public ICollection<TrackPoint> Points { get; }
}

public class TrackPoint
{
   [Key]
   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public long Id { get; set; }

   public long TrackId { get; set; }
   public required virtual Track Track { get; set; }

   public required double Latitude { get; set; }
   public required double Longitude { get; set; }
}

This design suffices for the creation of the desired database tables. However, when posting a list of track points for creation, I don't need or want to supply track data within each track point. I have a track id defined in the endpoint: /track/44/points. However, because the DB definition requires a track for integrity constraints, the controller complains when posting the JSON content without a Track property defined.

{
   points: [{
      latitude: 1.0,
      longitude: 1.0
   }]
}

I can obviously create a new TrackPointDTO model with the TrackPoint DB relation fields removed (or use inheritance to avoid re-defining the same fields), but then my controller has to copy all the fields from the de-serialized TrackPointDTO object into a newly created TrackPoint object.

Ultimately I'm wondering if there's a cleaner way to stay within a single model that supports DB and constraint definitions as well as JSON transfer definitions. I recognize that the problem is that I want to both require the Track property for a DB model and allow it to be null for the JSON model which is an obvious conflict. I'm just wondering if the only solution is duplication and property copying.


Solution

  • You should have separate models for entities and for presentation since they serve different purposes and you want full control over both what the user sees and what you have in DB. Instead of copying properties in the controller explicitly, use AutoMapper then this is very clean ie.

    var trackPointToCreate = _mapper.Map<Trackpoint>(createTrackpointDto);
    
    var createdTrackpoint = await _trackpointService.CreateTrackpointAsync(trackPointToCreate);
    
    return Ok(_mapper.Map<TrackPointDto>(createdTrackpoint))
    

    With these separate models you can then even change the names of properties, add validation attributes etc. (just remember to map these differing property names with the AutoMapper definition).

    AutoMapper tutorial: dotnettutorials.net/lesson/automapper-in-c-sharp