Как вывести в MVC только указанные c записей из таблицы базы данных? - PullRequest
1 голос
/ 27 мая 2020

Я новенький с MVC. Я пытаюсь разработать приложение для бронирования автомобиля. У меня есть таблица с названием Reservations и одна с именем Cars . Я должен отображать доступные автомобили для пользователей с указанным местоположением, временным интервалом (автомобили, которые в данный момент не зарезервированы).

Моя идея состоит в том, чтобы создать представление для получения данных от пользователя (местоположение, временной интервал), и после того, как он отправит эти данные, он будет перенаправлен на страницу, которая отображает эти записи (сведения об автомобиле). Проблема в том, что я действительно не знаю, как привязать представления и как отображать их из списка.

Вот что я пробовал:

Мой контроллер:

public ActionResult DisplayCars()
        {
            return View();
        }

Здесь я попытался составить список и добавить полученные записи из базы данных

 [HttpPost]
        public ActionResult AvailableCars([Bind(Include = "StartDate,EndDate,Location")] Reservations reservation)
        {
            List<Cars> carList = null;

            if (ModelState.IsValid)
            {
                if (reservation.StartDate != null && reservation.EndDate != null && reservation.Location != null)
                {
                    carList = db.Database.SqlQuery<Cars>("Select * from Cars WHERE Location = @location AND CarID NOT IN" +
                         "(Select CarID FROM Reservations WHERE NOT (StartDate > @endDate) OR (EndDate < @startDate))",
                         new SqlParameter("location", reservation.Location), new SqlParameter("endDate", reservation.EndDate), new SqlParameter("startDate", reservation.StartDate)).ToList<Cars>();
                }
                else if(reservation.StartDate == null && reservation.EndDate == null && reservation.Location != null)
                {
                    carList = db.Database.SqlQuery<Cars>("Select * from Cars WHERE Location = @location",
                         new SqlParameter("location", reservation.Location)).ToList<Cars>();
                }
                else if(reservation.StartDate != null && reservation.EndDate != null && reservation.Location == null)
                {
                    carList = db.Database.SqlQuery<Cars>("Select * from Cars WHERE CarID NOT IN" +
                        "(Select CarID FROM Reservations WHERE NOT (StartDate > @endDate) OR (EndDate < @startDate))",
                        new SqlParameter("endDate", reservation.EndDate), new SqlParameter("startDate", reservation.StartDate)).ToList<Cars>();
                }
            }

            if(carList == null)
            {
                ModelState.AddModelError("", "No available cars");
            }

            return View(carList);
        }

Вот мой вид для получения ввода от пользователя:

@model RentC.UI.Models.Reservations

@{
    ViewBag.Title = "DetailsAvailableCars";
}

<h2>DetailsAvailableCars</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.StartDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { @class = "form-control date-picker" } })
                @Html.ValidationMessageFor(model => model.StartDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.EndDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { @class = "form-control date-picker" } })
                @Html.ValidationMessageFor(model => model.EndDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Location, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Location, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Location, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Search" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "AvailableCars")
</div>

Это Вид для отображения записей

@model IEnumerable<RentC.UI.Models.Cars>

@{
    ViewBag.Title = "Available Cars List";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Plate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Manufacturer)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Model)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.PricePerDay)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Location)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Plate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Manufacturer)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Model)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.PricePerDay)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Location)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.CarID }) |
            @Html.ActionLink("Details", "Details", new { id=item.CarID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.CarID })
        </td>
    </tr>
}

</table>

Это моя модель автомобиля

 public partial class Cars
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Cars()
        {
            this.Reservations = new HashSet<Reservations>();
        }

        public int CarID { get; set; }
        [Display(Name = "Cart Plate")]
        public string Plate { get; set; }
        public string Manufacturer { get; set; }
        public string Model { get; set; }
        public decimal PricePerDay { get; set; }
        public string Location { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Reservations> Reservations { get; set; }
    }
}

Это модель для бронирования

public partial class Reservations
    {
        public int ReservationID { get; set; }
        public int CarID { get; set; }
        public int CustomerID { get; set; }
        public System.DateTime StartDate { get; set; }
        public System.DateTime EndDate { get; set; }

        public virtual Cars Cars { get; set; }
    }

Пожалуйста, помогите мне советами или идеи. Спасибо!

1 Ответ

1 голос
/ 28 мая 2020

Не могу сказать, какая именно у Вас проблема, но мне нравится попытка, поэтому я создаю для Вас пример ( ссылка ). Надеюсь, он даст вам некоторые идеи со всеми комментариями.

В любом случае вот основные файлы:

HomeController.cs

using CarReservations.Models;
using CarReservations.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CarReservations.Controllers
{
    [Route("[controller]")]
    public class HomeController : Controller
    {
        private readonly MyDbContext dbContext;

        public HomeController(MyDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        // 1. http://localhost:53436/Home/AvailableCars
        // ASP.NET Core cannot bind cars parameter neither [From*]  so it passes all Cars from our in-memory DB
        // We click <a asp-action="DisplayCars">Search for cars</a> in Home/AvailableCars.cshtml ----> DisplayCars action

        // 4. We got redirected from POST with model provided so cars are our result from POST not result from DB
        [HttpGet]
        // determinamtes URL: [Route("[controller]")]/[Route("AvailableCars")] -> Home/AvailableCars
        [Route("AvailableCars")]
        // determinates action name used by code (eg. new View()/asp-action): [ActionName("AvailableCars")] -> new View() = new View("AvailableCars")
        [ActionName("AvailableCars")]
        public async Task<IActionResult> AvailableCarsAsync(IEnumerable<Car> cars) => View(cars.Any()
            ? cars
            : await dbContext.Cars.AsNoTracking().ToListAsync());

        // 2. http://localhost:53436/Home/DisplayCars
        // ASP.NET Core cannot bind carSearch parameter neither [From*]  so it passes null
        // We submit a form ----> POST DisplayCars action (DisplayCarsPostAsync)
        [HttpGet]
        [Route("DisplayCars")]
        [ActionName("DisplayCars")]
        public IActionResult DisplayCarsGet(CarSearchViewModel carSearch) => View(carSearch);

        // 3. http://localhost:53436/Home/DisplayCars
        // got redirected from GET -> POST -> do stuff -> redirect back either to the same view (GET) on error or to some other GET action.
        [HttpPost]
        [Route("DisplayCars")]
        [ActionName("DisplayCars")]
        public async Task<IActionResult> DisplayCarsPostAsync(CarSearchViewModel carSearch)
        {
            if (ModelState.IsValid)
            {
                // liverage EF ORM
                // just build a query, hold on with execution
                IQueryable<Car> cars = dbContext.Cars
                    .Where(car => string.IsNullOrEmpty(carSearch.Location)
                        || car.Location.Equals(carSearch.Location));

                if (carSearch.StartDate.HasValue && carSearch.EndDate.HasValue)
                {
                    // hold on with execution
                    IQueryable<int> excludedCarsIds = dbContext.Reservations
                        .Where(reservation => reservation.EndDate < carSearch.StartDate.Value
                            && reservation.StartDate > carSearch.EndDate.Value)
                        .Select(reservation => reservation.CarID);

                    cars = cars.Where(car => !excludedCarsIds.Contains(car.CarID));
                }

                // ToListAsync will execute the query
                return View("AvailableCars", await cars.AsNoTracking().ToListAsync());
            }

            ModelState.AddModelError("", "No available cars");
            return View(carSearch);
        }
    }
}

CarSearchViewMode.cs

using System;

namespace CarReservations.ViewModels
{
    public class CarSearchViewModel
    {
        public string Location { get; set; }
        public DateTime? StartDate { get; set; }
        public DateTime? EndDate { get; set; }
    }
}

Что я сделал:

  • заменил исходный SQL на EF DbSet и LINQ. Найти путь проще, хотя SQL может не переводиться как sh.
  • заменить HTML вспомогательные методы на asp помощники тегов - просто выбор. Вы новичок, поэтому я решил показать вам ASP. NET Синтаксис помощников основных тегов
  • представить концепцию ViewModels: модели должны оставаться связанными только с записями БД, то, что мы отображаем, должно быть построено из эти модели и должны быть адаптированы к виду c (таким образом, они называются ViewModels), так что View может просто отображать дату, не пытаясь каким-либо образом ее сформировать.

В общем, как это работает (см. комментарии с 1-4):

  1. GET AvailableCars со всеми автомобилями
  2. -> GET DisplayCars (go в форму поиска)
  3. - > POST DisplayCars (форма отправки, проверка, запрос базы данных, возврат результатов) -> GET AvailableCars только с результатами.

(3) - это шаблон Post / Redirect / Get.

Удачи в обучении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...