如何解决C#实体框架核心在GET请求中返回太多相关实体
我正在使用.NET Core API,该API使用Entity Framework Core并具有以下实体:
-
User
,其中包含Appointments
和Orders
的列表
-
Appointments
可以下订单 -
Orders
具有零件列表 -
Parts
仅包含名称和价格
当我尝试对/order
进行索引请求时,它会返回相关实体,这很好,但是,它会继续添加或嵌套相关项目。我希望它返回相关的Appointment
,User
和Parts
,但没有比这更深的层次了。
我在想我在模型/数据库中输入了错误的外键,或者我的包含错误了。
下面是我所有相关的代码,请让我知道是否添加了太多上下文。
我的模型看起来像这样(通常是分开的文件,但是为了简洁起见,在一个代码块中)
public class User
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phonenumber { get; set; }
public string PostalCode { get; set; }
public string Housenumber { get; set; }
public string Streetname { get; set; }
public string Cityname { get; set; }
public List<Appointment> Appointments { get; set; }
public List<Order> Orders { get; set; }
[JsonIgnore] //Prevents password from being serialized & returned in API response(s)
public string Password { get; set; }
}
public class Appointment
{
public int Id { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public Order Order { get; set; }
public string GeneralProblem { get; set; }
public enum ProblemType
{
Problem1,Problem2,}
public Boolean AcceptedAppointment { get; set; }
public Boolean TermsOfService { get; set; }
public string AppointmentDue { get; set; }
public Boolean InQueue { get; set; }
public DateTime Timestamp { get; set; }
}
public class Order
{
[Key]
public int Id { get; set; }
public Appointment Appointment { get; set; }
public User User { get; set; }
public int UserId { get; set; }
public int AppointmentId { get; set; }
public float TotalCost { get; set; }
public List<Part> Parts { get; set; }
}
public class Part
{
[Key]
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public float Price { get; set; }
}
我的ApplicationDbContext
看起来像这样:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Appointment> Appointments { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Part> Parts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Appointment>()
.HasOne(a => a.User)
.WithMany(u => u.Appointments);
modelBuilder.Entity<Order>()
.HasOne(o => o.Appointment)
.WithOne(a => a.Order)
.HasForeignKey<Order>(b => b.AppointmentId);
modelBuilder.Entity<Order>()
.HasMany(o => o.Parts)
.WithOne(t => t.Order);
}
}
当前,我正在尝试通过以下步骤为订单建立索引并尝试收集相关实体(请注意,我使用的是界面和存储库设计模式,但是为了简洁起见并未添加这些功能)
public class OrderRepository : IOrderRepository
{
private readonly ApplicationDbContext _context;
public IEnumerable<Order> FindAll()
{
//Adding parts to related order
var orderContext = _context.Orders
.Include(Order => Order.Parts)
.Include(Order => Order.Appointment)
.ThenInclude(Order => Order.User)
.ToList();
return orderContext ;
}
我希望JSON输出如下所示:
{
"id": 2,"appointment": {
"id": 1,"userId": 1,"generalProblem": "Lorem ipsum dolor sit amet,consectetur adipiscing elit. Sed ut orci sit amet nisi egestas semper. ","acceptedAppointment": true,"termsOfService": false,"appointmentDue": "08/14/2020","inQueue": false,"timestamp": "0001-01-01T00:00:00"
},"user": {
"id": 1,"name": "Barry","email": "barry@mail.nl","phonenumber": "12345678","postalCode": "4201JA","housenumber": "44","streetname": "Somewhere","cityname": "NoWhere","appointments": [],"orders": [],"password": "12345678"
},"appointmentId": 1,"totalCost": 155.44,"parts": [
{
"id": 1,"orderId": 2,"name": "Test","description": "Test","price": 100.0
},{
"id": 2,"name": "Wasbak","description": "Grote marmeren wasbak","price": 2000.0
}
]
}
但是不幸的是,结果是这样的:
{
"id": 2,"user": {
"id": 1,"appointments": [
{
"id": 2,"order": {
"id": 4,"appointmentId": 2,"totalCost": 100.0,"parts": [
{
"id": 3,"orderId": 4,"description": "test","price": 123.0
}
]
},"generalProblem": "BLABLABLA","acceptedAppointment": false,"timestamp": "0001-01-01T00:00:00"
}
],"orders": [
{
"id": 4,"appointment": {
"id": 2,"timestamp": "0001-01-01T00:00:00"
},"parts": [
{
"id": 3,"price": 123.0
}
]
}
],"password": "12345678"
},"appointments": [
{
"id": 1,"postcode": null,"timestamp": "0001-01-01T00:00:00"
},{
"id": 2,"order": {
"id": 4,"price": 123.0
}
]
},"timestamp": "0001-01-01T00:00:00"
}
],"orders": [
{
"id": 4,"appointment": {
"id": 2,"timestamp": "0001-01-01T00:00:00"
},"parts": [
{
"id": 3,"price": 123.0
}
]
}
],"price": 2000.0
}
]
}
我使用的包含错误吗?还是我的模型设置错误?
解决方法
我认为您的模型还可以,而且急切的加载也可以(包括您正在执行的Include)。您需要进行联接,因为您需要响应中的数据。
唯一的问题是您应该使用DTO:例如Automapper是一个很好的Nuget程序包。
借助DTO,您可以消除这种冗长的内容。
仅举例说明如何进行。
public class OrderDto
{
public int Id { get; set; }
public AppointmentDto Appointment { get; set; }
public UserDto User { get; set; }
public int UserId { get; set; }
public int AppointmentId { get; set; }
public float TotalCost { get; set; }
public List<PartDto> Parts { get; set; }
}
public class AppointmentDto
{
public int Id { get; set; }
public int UserId { get; set; }
public string GeneralProblem { get; set; }
public Boolean AcceptedAppointment { get; set; }
public Boolean TermsOfService { get; set; }
public string AppointmentDue { get; set; }
public Boolean InQueue { get; set; }
public DateTime Timestamp { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phonenumber { get; set; }
public string PostalCode { get; set; }
public string Housenumber { get; set; }
public string Streetname { get; set; }
public string Cityname { get; set; }
}
public class PartDto
{
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public float Price { get; set; }
}
然后在您的控制器中执行以下操作:
// GET: api/Orders
[HttpGet("")]
public async Task<ActionResult<OrderDto>> GetAllOrders()
{
var orders = _orderRepository.FindAll();
if (orders == null)
{
return NotFound();
}
return _mapper<IList<OrderDto>>(orders);
}
如您所见,我从所有DTO中删除了所有不必要的导航属性,因此.Net Core不会映射它。这样,您将获得一个更扁平的json。 可以通过Nuget来安装Automapper,只需要您configure映射即可,只需几行代码即可。 如果DTO上没有导航属性,那么所有不必要的连接都将无法完成,这意味着性能更高,并且没有“循环引用”。
P.s使用了您需要的许多DTO,请记住在配置中添加映射以使用它们。 DTO可能与Model完全不同,这是Automapper的一大优点。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。