简体   繁体   中英

MVC 5 EF 6 - How to Search a Table Using Related Table Object Criteria

I need to display a resulting table of PO Requests which includes the PO Items (this part I figured out) and provide search functionality for all items displayed (this part I got mostly figured out).

Using the code below, which is a slightly stripped down version, I am able to display the data I need and I am able to search for nearly all I need, as long as it is data from the PORequests model (this is the "parent model"). When I try to search using the "child model," POItems, the actual objects (ID, Description, etc.) are not accessible. This was built using DatabaseFirst model and EF6.x DbContextGenerator.

//POItemData ViewModel
using FinanceSearch.Models;
namespace FinanceSearch.ViewModels
{
    public class POItemData
    {
        public PagedList.IPagedList<PORequest> PORequests { get; set; }
        public PagedList.IPagedList<POItem> POItems { get; set; }
    }
}

//POItems Model
namespace FinanceSearch.Models
{
    using System;
    using System.Collections.Generic;

    public partial class POItem
    {
        public int ID { get; set; }
        public int Amount { get; set; }
        public string Description { get; set; }

        public virtual PORequest PORequest { get; set; }
    }
}

//PORequest Model
namespace FinanceSearch.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

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

        //other relevant stuff

        public virtual ICollection<POItem> POItems { get; set; }

    }
}


//Controller
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using FinanceSearch.Models;
using PagedList;
using System.Web.UI.WebControls;
using System.Data.Entity.SqlServer;
using FinanceSearch.ViewModels;

namespace FinanceSearch.Controllers
{
    public class PORequestsController : Controller
    {
        private Finance db = new Finance();



        public ActionResult Index(int? id, int? page, string sortOrder, string currentFilter, string poNumber,
           string AppropNumber, string ContractNumber, string ItemDescription)
        {

            ViewBag.CurrentSort = sortOrder;
            ViewBag.POSortParm = String.IsNullOrEmpty(sortOrder) ? "PONumber_desc" : "";
            ViewBag.AppropNumberSortParm = sortOrder == "AppropNumber" ? "AppropNumber_desc" : "AppropNumber";
            ViewBag.ContractNumberSortParm = sortOrder == "ContractNumber" ? "ContractNumber_desc" : "ContractNumber";


            if (poNumber != null)
            {
                page = 1;
            }
            else
            {
                ponumber = currentFilter;
            }

            //int pageSize = 3;
            int pageNumber = (page ?? 1);

            var viewModel = new POItemData();

            viewModel.PORequests = db.PORequests
               .Include(i => i.POItems)
               .OrderBy(i => i.ID).ToPagedList(pageNumber, 5);

            if (!String.IsNullOrEmpty(poNumber))
            {
                viewModel.PORequests = viewModel.PORequests.Where(s => s.PONumber.Contains(ponumber)).ToPagedList(pageNumber, 5);
            }
            if (!string.IsNullOrEmpty(AppropNumber))
            {
                viewModel.PORequests = viewModel.PORequests.Where(x => x.AppropNumber.Contains(AppropNumber)).ToPagedList(pageNumber, 5);
            }
            if (!string.IsNullOrEmpty(ContractNumber))
            {
                viewModel.PORequests = viewModel.PORequests.Where(x => x.ContractNumber.Contains(ContractNumber)).ToPagedList(pageNumber, 5);
            }
            if (!string.IsNullOrEmpty(ItemDescription))
            {

            }

In the ItemDescription if statement, something like the following would be nice:

if (!string.IsNullOrEmpty(ItemDescription))
{
viewModel.PORequests = viewModel.PORequests.Where(x => x.POItems.Description.Contains(ItemDescription)).ToPagedList(pageNumber, 5);
}

The x.POItems.Description part doesn't exist in this sense. Apparently related to it being a list. Continuing remainder of code...

            switch (sortOrder)
            {
                case "PONumber_desc":
                    viewModel.PORequests = viewModel.PORequests.OrderByDescending(s => s.PONumber).ToPagedList(pageNumber, 5);
                    break;
                case "AppropNumber":
                    viewModel.PORequests = viewModel.PORequests.OrderBy(s => s.AppropNumber).ToPagedList(pageNumber, 5);
                    break;
                case "AppropNumber_desc":
                    viewModel.PORequests = viewModel.PORequests.OrderByDescending(s => s.AppropNumber).ToPagedList(pageNumber, 5);
                    break;
                case "ContractNumber":
                    viewModel.PORequests = viewModel.PORequests.OrderBy(s => s.ContractNumber).ToPagedList(pageNumber, 5);
                    break;
                case "ContractNumber_desc":
                    viewModel.PORequests = viewModel.PORequests.OrderByDescending(s => s.ContractNumber).ToPagedList(pageNumber, 5);
                    break;
                default: 
                    viewModel.PORequests = viewModel.PORequests.OrderBy(s => s.PONumber).ToPagedList(pageNumber, 5);
                    break;
            }


            return View(viewModel);
        }

In the code above, I included my paging and sorting stuff as well, because in the tutorials and answers I have come across, it appears to make a difference in how it all turns out, and is required for this project.

Below is the Index/View I am using to display the results:

//View    (Index)    
@model FinanceSearch.ViewModels.POItemData
@using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />

@{
    ViewBag.Title = "PORequests";
}

<h2>Finance</h2>

@*<p>
    @Html.ActionLink("Create New", "Create")
</p>*@

<p>
    <button class="btn btn-default" data-toggle="collapse" href="#MainFilter" @*data-target="#MainFilter"*@ aria-multiselectable="true" aria-expanded="true">Filter By...</button>
</p>

@*<div id="accordion" role="tablist" aria-multiselectable="true">*@
@using (Html.BeginForm("Index", "PORequests", FormMethod.Get))
{
    <div id="MainFilter" class="collapse">

        <table class="table-responsive">
            <tr>
                <td>
                    Item: 
                </td>
                <td>
                    @Html.TextBox("ItemDescription", ViewBag.CurrentFilter as string) //this is where the user would search items using a string
                </td>
            </tr>
            <tr>
                <td>
                    PO #:
                </td>
                <td>
                    @Html.TextBox("PONumber", ViewBag.CurrentFilter as string)
                </td>
            </tr>
        </table>
        <br />
        <p>
            <button class="btn btn-primary btn-sm" data-parent="#MainFilter" data-toggle="collapse" href="#SubFilterPOInfo" @*data-target="#SubFilterPOInfo"*@>Filter by PO Info...</button>
        </p>

        <div id="SubFilterPOInfo" class="collapse">
            <table class="table-responsive">
                <tr>
                    <td>
                        AppropNumber:
                    </td>
                    <td>
                        @Html.TextBox("AppropNumber", ViewBag.CurrentFilter as string)
                    </td>
                </tr>
                <tr>
                    <td>
                        Contract Number:
                    </td>
                    <td>
                        @Html.TextBox("ContractNumber", ViewBag.CurrentFilter as string)
                    </td>
                </tr>
            </table>
        </div>

}

<div style="overflow-x: scroll">

    <table class="table" style="white-space:nowrap">

        <tr>
            <th></th>
            <th></th>
            <th>
                @Html.ActionLink("PONumber", "Index", new { sortOrder = ViewBag.POSortParm, currentFilter = ViewBag.CurrentFilter })
            </th>
            <th>
                @Html.ActionLink("AppropNumber", "Index", new { sortOrder = ViewBag.AppropNumberSortParm, currentFilter = ViewBag.CurrentFilter })
            </th>
            <th>
                @Html.ActionLink("ContractNumber", "Index", new { sortOrder = ViewBag.ContractNumberSortParm, currentFilter = ViewBag.CurrentFilter })
            </th>
        </tr>

        @foreach (var item in Model.PORequests)
            {
            <tr>
                <td>
                    @*@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |*@
                    @Html.ActionLink("Details", "Details", new { id = item.ID }) |
                    @*@Html.ActionLink("Delete", "Delete", new { id = item.ID })*@
                </td>
                <td>
                    //I am able to list the related items in the PORequests table
                    @foreach (var poitem in item.POItems)
                    {
                        @poitem.Description<br />
                    }

                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.PONumber)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.AppropNumber)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.ContractNumber)
                </td>

            </tr>

        }
    </table>

</div>
<br />
//paging and sorting stuff
    Page @(Model.PORequests.PageCount < Model.PORequests.PageNumber ? 0 : Model.PORequests.PageNumber) of @Model.PORequests.PageCount
    @Html.PagedListPager(Model.PORequests, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))

To summarize:

I don't seem to comprehend how to use the variable ItemDescription to search within the POItems list, and get the PORequest table, which includes the POItem table as a related object, to display the results. My other searches all function as expected.

I have searched, on this site in particular, but any of the similar questions involve the view end of it just displaying each item in the list, which I am able to do, or creating/editing functionality, or, perhaps, they are beyond my understanding of MVC enough where they didn't appear to be a solution.

Here are a few such examples:

MVC Code First: One-to-many relationship between own model and SimpleMembership user

EntityFramework 6. How to get related objects?

https://stackoverflow.com/questions/26372533/add-the-list-of-object-to-parent-object-using-mvc-5-and-ef-6

Any help would be greatly appreciated.

Drill down to the items in the search expression:

if (!string.IsNullOrEmpty(ItemDescription))
{
    viewModel.PORequests = viewModel.PORequests.Where(x => x.POItems
        .Any(i => i.Description.Contains(ItemDescription)))
        .ToPagedList(pageNumber, 5);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM