Как выбрать только одну запись из БД, а также включить ее данные из связанных таблиц - PullRequest
0 голосов
/ 04 июня 2019

Я пишу Entity Framework Command для выбора только одной записи (книг) из базы данных.Это должно быть показано через API, где пользователь должен предоставить идентификатор через URL.Кроме того, поскольку таблица связана с другими таблицами (писатели, жанры), необходимо включить соответствующие записи из этих таблиц.Книга может иметь больше жанров и сохраняет ее в таблице BookGenres, которая затем связана с таблицей жанров.Также в Книге есть один Writer из таблицы с тем же именем.BookDto - это объект, который возвращает только соответствующие данные для конечного пользователя.Команда выглядит следующим образом:

EfGetBookCommand: IGetBookCommand

 private readonly LibraryContext _context;

    public EfGetBookCommand(LibraryContext context)
    {
        _context = context;
    }

    public BookDto Execute(int request)
    {
        //var book = _context.Books.AsQueryable();
        var book = _context.Books.AsQueryable();
        if (book == null)
        {
            throw new Exception();
        }

        var result = book
            .Include(b => b.Writer)
            .ThenInclude(w => w.Name)
            .Include(b => b.BookGenres)
            .ThenInclude(bg => bg.Genre)
            .Where(b => b.Id == request)
            .First();

        return new BookDto
        {
            Id = result.Id,
            Title = result.Title,
            Writer = result.Writer.Name,
            Description = result.Description,
            AvailableCount = result.AvailableCount,
            Count = result.Count,
            BookGenres = result.BookGenres.Select(bg => bg.Genre.Name)
        };

Когда я пытаюсь сделать это в почтальоне с помощью запроса GET, например: http://localhost:55666/api/books/4, я получаю 404. Я не могу использоватьнайти, так как я не могу объединить его с Включить.Я покажу соответствующие классы.

У меня уже есть подобная команда для возврата всех книг, и она работает, поэтому я не могу найти, что с этим не так.

BooksController (в приложении API)

    public class BooksController : ControllerBase
{
    private IGetBooksCommand _command;
    private IGetBookCommand _command2;

    public BooksController(IGetBooksCommand command, IGetBookCommand command2)
    {
        _command = command;
        _command2 = command2;
    }
 [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        try
        {
            var BookDto = _command2.Execute(id);
            return Ok(BookDto);
        }
        catch(Exception e)
        {
            return NotFound();
        }
    }

BookDto

public class BookDto
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Writer { get; set; }
    public string Description { get; set; }
    public int AvailableCount { get; set; } 
    public int Count { get; set; }
    public IEnumerable<string> BookGenres { get; set; }
}

Book (класс домена для подхода Entity Framework, первый подход)

   public class Book : BaseEntity
{
    public string Title { get; set; }
    public int WriterId { get; set; }
    public Writer Writer { get; set; }
    public string Description { get; set; }
    public int AvailableCount { get; set; }
    public int Count { get; set; } reserved or not
    public ICollection<BookGenre> BookGenres { get; set; }
    public ICollection<BookReservation> BookReservations { get; set; }
}

BookGenre (DomainClass)

public class BookGenre
{
    public int BookId { get; set; }
    public int GenreId { get; set; }
    public Book Book { get; set; }
    public Genre Genre { get; set; }
}

Genre (DomainClass)

public class Genre : BaseEntity
{
    public string Name { get; set; }
    public ICollection<BookGenre> BookGenres { get; set; }
}

Writer (DomainClass)

ICommand

    public interface ICommand<TRequest>
{
    void Execute(TRequest request);
}
public interface ICommand<TRequest, TResult>
{
    TResult Execute(TRequest request);
}

IGetBookCommand

    public interface IGetBookCommand : ICommand<int, BookDto>
{

}

Я должен получить объект BookDtoвернулся в JSON, но я получаю ошибку 404.

Ответы [ 2 ]

0 голосов
/ 04 июня 2019

попробуйте что-нибудь в этом духе. Ваш начальный запрос вызывает AsQueryable (), что приведет к выполнению sql, и вы потеряете ленивую загрузку. Вы можете объединить всю свою логику sql в основной запрос и сразу получить все присоединяющиеся таблицы. Это может иметь несколько синтаксических ошибок, так как у меня нет всего кода.

public BookDto Execute(int request)
    {
        var book = _context.Books
            .Single(b => b.Id == request)
            .Select(s => new BookDto() {
               Id = s.Id,
               Title = s.Title,
               Writer = s.Writer.Name,
               Description = s.Description,
               AvailableCount = s.AvailableCount,
               BookGenres = s.BookGenres.ToList()
        });
    }
0 голосов
/ 04 июня 2019

Я подозреваю что-то в строке var BookDto = _command2.Execute(id);, когда я проверяю вашу кодовую базу, я мог видеть класс с таким именем уже существует, и вы пытаетесь воссоздать его снова.

Так как вы возвращаете return NotFound(); просто попытайтесь убедиться, что ваша маршрутизация выполнена правильно, и действие запускается.

Я предлагаю использовать AttributeRouting как,

 [Route("~/api/books/{id}")] [HttpGet]
 public IActionResult Get(int id)
{
    try
    {
        var result= _command2.Execute(id);
        return Ok(result);
    }
    catch(Exception e)
    {
        // Try returning some other exception other than 404.
    }
}
...