Я стараюсь не раскрывать данные своего уровня данных на уровне API, поэтому все нужно делать через посредник запросы.
Ниже приведены мои сущности, контроллер и обработчик запросов.
// Сущности
Код: Выделить всё
public class Course : BaseAuditableEntity
{
public string? Name { get; set; }
public Guid StudentId { get; set; }
public virtual Student? Student { get; set; }
}
public class Student : BaseAuditableEntity
{
public string? Name { get; set; }
public virtual ICollection Courses{ get; private set; } = new List();
}
Код: Выделить всё
public record GetRawCoursesQuery : IRequest;
public class GetCoursesQueryHandler : IRequestHandler
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
public GetCoursesQueryHandler(IApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public Task Handle(GetRawCoursesQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(_context.Courses.AsQueryable());
}
}
Код: Выделить всё
[HttpGet("odata")]
[EnableQuery]
public async Task GetCoursesAsync(
[FromQuery] int top,
[FromQuery] int skip,
[FromQuery] string orderby,
[FromQuery] string filter,
[FromQuery] string expand)
{
var query = await _sender.Send(new GetRawCoursesQuery());
return Ok(query);
}
Код: Выделить всё
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet("Courses");
var course = builder.EntityType();
course.ContainsOptional(t => t.Student);
builder.EntitySet("Students");
return builder.GetEdmModel();
}
Кроме того, если кому-то интересно, почему в моем действии используется FromQuery, они необходимы, поскольку я использую NSwag для создания своего APIClient, и это единственный способ для NSwag увидеть конечную точку OData!
Проблема:
Вышеупомянутое работает нормально, однако оно работает нормально, потому что я использую ' Объекты «Курс» и «Студент», но мне нужно, чтобы это использовало DTO, однако когда я это делаю, все работает, кроме Развернуть
Вот изменения, которые я внес
Код: Выделить всё
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet("Courses");
var course = builder.EntityType();
course.ContainsOptional(t => t.Student);
builder.EntitySet("Students");
return builder.GetEdmModel();
}
public record GetRawCoursesQuery : IRequest;
public class GetCoursesQueryHandler : IRequestHandler
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
public GetCoursesQueryHandler(IApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public Task Handle(GetRawCoursesQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(_mapper.ProjectTo(_context.Courses));
}
}
public class CourseDto
{
public string? Name { get; set; }
public Guid StudentId { get; set; }
public virtual StudentDto? Student { get; set; }
private class Mapping : Profile
{
public Mapping()
{
CreateMap()
.ForMember(dest => dest.Student, opt => opt.ExplicitExpansion());
}
}
}
public class StudentDto
{
public string? Name { get; set; }
private class Mapping : Profile
{
public Mapping()
{
CreateMap();
}
}
}
Все работает нормально, кроме Expand, когда я вызываю URL-адрес типа
https://localhost:5001/odata/Courses?expand=Student
, который, как ожидается, включите Student в возвращаемый результат внутри объекта Course, но Student возвращает значение null!
Похоже, что проблема может быть связана с ProjectTo, я проверил это, включив свойство вручную в ProjectTo и это сработало, поэтому я думаю, что OData нужно каким-то образом сообщить ProjectTo о включении расширенных свойств!
Буду признателен, если кто-нибудь поможет мне понять, в чем здесь проблема!
Подробнее здесь: https://stackoverflow.com/questions/784 ... -with-dtos