0

I am working on a project that users can add/edit/delete a book from the database and reserve it. Basically a library database. In my user table(TblUser) I have userId(PK), name, email etc.. In my book table(TblBook) I have bookID(PK), Bookname, author etc. And Finally I have the TblBookStatus which has resID(PK), bookID, userID and status. I did not connect bookID and userID as foreign key due to some project specific reasons. When a user reserves a book, the userID, bookID and status has been added as a row on TblBookStatus table. What I am trying to do is, I want to display the reserved books by a user(TblBookStatus). here is my C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LibMan.Models.DB;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;

namespace LibMan.Pages
{
    public class LibraryModel : PageModel
    {
        private readonly LibMan.Models.DB.LibManContext _context;
        public string Message { get; set; }
        public LibraryModel(LibMan.Models.DB.LibManContext context)
        {
            _context = context;
        }
        public IList<TblBookStatus> TblBookStatus { get; set; }
        public IList<TblBook> TblBook { get; set; }
        public IList<TblBook> DisplayBook { get; set; }

        public async Task OnGetAsync()
        {
            TblBookStatus = await _context.TblBookStatus.ToListAsync();
            TblBook = await _context.TblBook.ToListAsync();
            foreach(var item in TblBook)
            {
                foreach(var item2 in TblBookStatus)
                {
                    if(item.BookId == item2.BookId)
                    {
                        DisplayBook.Add(item);
                    }
                }
            }
        }
    }
}

I tried to turn both tables into lists and check for the intersecting book ID's and make a new list to display them, but I get the error : NullReferenceException: Object reference not set to an instance of an object. on the line DisplayBook.Add(item);

I have seen people writing SQL commands, but I am not sure If I should do it. Here is the HTML side

@page
@model LibMan.Pages.LibraryModel
@{
    ViewData["Title"] = "Library";
    Layout = "~/Pages/Shared/_postLoginLayout.cshtml";
}

<h1>Library</h1>

<p>
    <a asp-page="Create">Add a new Book</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Author)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Translator)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Publisher)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Description)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Category)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Status)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TblBook[0].Cover)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.DisplayBook)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Author)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Translator)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Publisher)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Description)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Category)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Status)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Cover)
                </td>
                <td>
                    <a asp-page="./GetBook" asp-route-id="@item.BookId">Get Book</a> |
                    <a asp-page="./Edit" asp-route-id="@item.BookId">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.BookId">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.BookId">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

Thanks for the help!

1 Answer 1

2

Intialize DisplayBook list in your constructor.

public LibraryModel(LibMan.Models.DB.LibManContext context)
        {
            _context = context;
             DisplayBook = new List<TblBook>();
        }

Also add this condition before your for loops

 if(TblBookStatus!=null && TblBook!=null) 
             {
            foreach(var item in TblBook)
              {
                foreach(var item2 in TblBookStatus)
                {
                    if(item.BookId == item2.BookId)
                    {
                        DisplayBook.Add(item);
                    }
                }
            }
          }

** (only suggestion )You can also make your nested for loop replace with lambda.

public async Task OnGetAsync()
        {
            TblBookStatus = await _context.TblBookStatus.ToListAsync();
            TblBook = await _context.TblBook.ToListAsync();
            if(TblBookStatus!=null && TblBook!=null) 
            {
              DisplayBook =  TblBook.Where(t=>TblBookStatus.Any(ts=>ts.BookId==t.BookId));
            }
        }

You can also make use of partial view to keep your razor code clean. Create partial view and pass it LibraryModel object as param and move from from to inside that partial view.

Sign up to request clarification or add additional context in comments.

3 Comments

Wow, I can't believe I missed something like this, was working on it for the past hour! Thanks alot!
by the way I tried your suggestion and used lambda, but I get the following error: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<LibMan.Models.DB.TblBook>' to 'System.Collections.Generic.IList<LibMan.Models.DB.TblBook>'. An explicit conversion exists (are you missing a cast?)
Just fixed it by changing DisplayBook's type to IEnumerable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.