我正在设计一个具有一组相对直接的模型和关系的 API。我能找到的很多文档和示例似乎都建议设计一个既充当数据库模型又充当 JSON 模型的模型。起初,这对于减少代码量来说似乎是理想的选择。然而,对于简单的关系,让单个模型满足 DB 模型和 JSON 模型的需求似乎很困难。我并不反对重复,但这似乎会导致重复的现场复制,我确信有更好的方法。
考虑一个轨迹表,每个轨迹都包含一个轨迹点列表。
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; }
}
这种设计足以创建所需的数据库表。但是,在发布用于创建的跟踪点列表时,我不需要或不想在每个跟踪点内提供跟踪数据。我在端点中定义了一个轨道 ID:
/track/44/points
。但是,由于数据库定义需要跟踪完整性约束,因此在发布未定义 Track
属性的 JSON 内容时,控制器会发出抱怨。
{
points: [{
latitude: 1.0,
longitude: 1.0
}]
}
我显然可以创建一个新的
TrackPointDTO
模型,并删除TrackPoint
数据库关系字段(或使用继承来避免重新定义相同的字段),但是我的控制器必须从反序列化的复制所有字段TrackPointDTO
对象转换为新创建的 TrackPoint
对象。
最终我想知道是否有一种更干净的方法来保留在支持数据库和约束定义以及 JSON 传输定义的单个模型中。我认识到问题是我希望数据库模型需要
Track
属性,并允许 JSON 模型为空,这是一个明显的冲突。我只是想知道唯一的解决方案是否是复制和属性复制。
您应该为实体和演示使用单独的模型,因为它们服务于不同的目的,并且您希望完全控制用户看到的内容和数据库中的内容。使用 AutoMapper 代替显式复制控制器中的属性,这样就非常干净了。
var trackPointToCreate = _mapper.Map<Trackpoint>(createTrackpointDto);
var createdTrackpoint = await _trackpointService.CreateTrackpointAsync(trackPointToCreate);
return Ok(_mapper.Map<TrackPointDto>(createdTrackpoint))
使用这些单独的模型,您甚至可以更改属性名称、添加验证属性等(只需记住将这些不同的属性名称与 AutoMapper 定义映射)。
AutoMapper 教程:dotnettutorials.net/lesson/automapper-in-c-sharp