'Foreign Key word display blank when the app is run

I have built a Book app in ASP.NET Core razor pages CRUD using Entity Framework. However, when I run the app and view it on https://localhost:44370/, the Foreign Key word appears blank. Here is my code:

Models Author

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace BookStore.Models
{
    public class Author
{
        public int ID { get; set; }
        
        [StringLength(50)]
        [Display(Name = "Country Name")]
        public string CountryName { get; set; }

        [StringLength(50)]
        [Display(Name = "Author Name")]
        public string AuthorName { get; set; }      

        
        [ForeignKey("AuthorID")]
        public ICollection<Book> Books { get; set; }

        [ForeignKey("AuthorID")]
        public ICollection<Tour> Tours { get; set; }
    }
 }

The Models Book class

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BookStore.Models
{
    public class Book
    {
        [Key]
        public int BookID { get; set; }

        [StringLength(50)]
        [Column("BookTitle")]
        [Display(Name = "Book Title")]
        public string BookTitle { get; set; }

        [StringLength(50)]
        [Column("BookPublisher")]
        [Display(Name = "Book Publisher")]
        public string BookPublisher { get; set; }        

        [ForeignKey("AuthorID")]
        public Author Author { get; set; }
        public int AuthorID { get; set; }

        
        public ICollection<BookReview> BookReviews { get; set; }
    }
}

Models Tour class

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BookStore.Models
{
    public class Tour
    {
        [Key]
        public int TourID { get; set; }

        [StringLength(50)]
        [Column("TourName")]
        [Display(Name = "Tour Name")]
        public string TourName { get; set; }

        [StringLength(50)]
        [Column("TourPlace")]
        [Display(Name = "Tour Place")]
        public string TourPlace { get; set; }        

        [ForeignKey("AuthorID")]
        public Author Author { get; set; }
        public int AuthorID { get; set; }

        
        public ICollection<BookRating> BookRating { get; set; }
    }
}

Initially, when I had scaffolded the Pages for the Book Folder and the Tour Folder, the generated Create.cshtml.cs and Edit.cshtml.cs pages showed the Foreign key as "CountryName" and so I modified it to "AuthorName"

Pages:Book:Create.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using BookStore.Models;

namespace BookStore.Pages.Books
{
    public class CreateModel : PageModel
    {
        private readonly BookStore.Models.BookWorkContext _context;

        public CreateModel(BookStore.Models.BookWorkContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
        ViewData["AuthorID"] = new SelectList(_context.Author, "ID", "AuthorName");
            return Page();
        }

        [BindProperty]
        public  Book Book { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Book.Add(Book);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

Data: 'DbInitilializer.cs'

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using BookStore.Models;


namespace BookStore.Data
{
    public class DbInitializer
    {
        public static void Initialize(BookWorkContext context)
        {
            context.Database.EnsureCreated();

            // Look for any Authors.
            if (context.Author.Any())
            {
                return;   // DB has been seeded
            }

            var Authors = new Author[]
            {
                new Author {CountryName="United States of America",AuthorName="John Coltrane"},
                new Author {CountryName= "United States of America",AuthorName= "Jim Meyers"}
            };

            foreach (Author a in Authors)
            {
                context.Author.Add(a);
            }
            context.SaveChanges();

            var Tours = new Tour[]
            {
                new Tour {AuthorID = Authors.Single(a => a.AuthorName == "John Coltrane").ID,TourName = "The Prairie Tour",TourPlace = "Town Center"},
                new Tour {AuthorID = Authors.Single(a => a.AuthorName == "Jim Meyers").ID,TourName = "Santa Barbara Tours",TourPlace = "Long Circular Mall"},
            };

            foreach (Tour t in Tours)
            {
                context.Tour.Add(t);
            }
            context.SaveChanges();

            var Books = new Book[]
            {
                new Book {AuthorID = Authors.Single(a => a.AuthorName == "Tim Hendricks").ID, BookTitle = "Three Stooges",BookPublisher = "Penguin"},
                new Book {AuthorID = Authors.Single(a => a.AuthorName == "Andy Ford").ID, BookTitle = "Tom Sawyer",BookPublisher = "Collins"},
            };

            foreach (Book b in Books)
            {
                context.Book.Add(b);
            }
            context.SaveChanges();
        }
    }
}

On running the app, if I try to create a new entry, I see the AuthorName in the dropdown field but once I save the new entry, the Foreign Key column is blank and the other columns are filled with data.
My question is how do I get the Foreign Key word "AuthorName" to appear in the app once I run the app?

I have attached a link to the Book Razor Page: - Book Razor Page



Solution 1:[1]

Here is a solution: -

1.Model: -

public class Author
{
    public int ID { get; set; }
    [StringLength(50)]
    [Display(Name = "Country Name")]
    public string CountryName { get; set; }

    [StringLength(50)]
    [Display(Name = "Author Name")]
    public string AuthorName { get; set; }

    [ForeignKey("AuthorID")]
    public ICollection<Book> Books { get; set; }

    [ForeignKey("AuthorID")]
    public ICollection<Tour> Tours { get; set; }
}
public class Book
{
    [Key]
    public int BookID { get; set; }
    [StringLength(50)]
    [Column("BookTitle")]
    [Display(Name = "Book Title")]
    public string BookTitle { get; set; }

    [StringLength(50)]
    [Column("BookPublisher")]
    [Display(Name = "Book Publisher")]
    public string BookPublisher { get; set; }

    //  [ForeignKey("AuthorID")]
    public Author Author { get; set; }
    public int AuthorID { get; set; }
}
public class Tour
{
    [Key]
    public int TourID { get; set; }
    [StringLength(50)]
    [Column("TourName")]
    [Display(Name = "Tour Name")]
    public string TourName { get; set; }

    [StringLength(50)]
    [Column("TourPlace")]
    [Display(Name = "Tour Place")]
    public string TourPlace { get; set; }

    // [ForeignKey("AuthorID")]
    public Author Author { get; set; }
    public int AuthorID { get; set; }

}

2.Create.cshtml: -

@page
@model CreateModel

<h4>Book</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Book.BookTitle" class="control-label"></label>
                <input asp-for="Book.BookTitle" class="form-control" />
                <span asp-validation-for="Book.BookTitle" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Book.BookPublisher" class="control-label"></label>
                <input asp-for="Book.BookPublisher" class="form-control" />
                <span asp-validation-for="Book.BookPublisher" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Book.AuthorID" class="control-label"></label>
                <select asp-for="Book.AuthorID" class ="form-control" asp-items="ViewBag.AuthorID"></select>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

3.Index.cshtml:

@page
@model IndexModel
<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Book[0].BookTitle)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Book[0].BookPublisher)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Book[0].Author)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Book) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.BookTitle)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.BookPublisher)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Author.AuthorName)
            </td>
            <td>
                <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>

3.Index.cshtml.cs:

public class IndexModel : PageModel
{
    private readonly RazorProj2_2.Models.RazorProj2_2Context _context;

    public IndexModel(RazorProj2_2.Models.RazorProj2_2Context context)
    {
        _context = context;
    }

    public IList<Book> Book { get;set; }

    public async Task OnGetAsync()
    {
        Book = await _context.Book
            .Include(b => b.Author).ToListAsync();
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wire_jp