Edit PartialView - How to load model

MaxPowers1982 81 Reputation points
2021-07-22T16:11:24.767+00:00

I would like to be able to perform edits using a partial view that is loaded via a modal. There are at least two problems with this attempt.

1) Upon attempting to load the modal, I get this error
117148-image.png

2) If I remove the offending line 28, the modal loads but ParentId and ChildName are blank, I would expect them to be populated from the id being passed into the partial view.

How can this be done properly?

Pages > Childs > Edit.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 Microsoft.EntityFrameworkCore;  
using TelerikTest.Models.Scaffold;  

namespace TelerikTest.Pages.Childs  
{  
    public class EditModel : PageModel  
    {  
        private readonly TelerikTest.Models.Scaffold.TelerikTestDBContext _context;  

        public EditModel(TelerikTest.Models.Scaffold.TelerikTestDBContext context)  
        {  
            _context = context;  
        }  

        [BindProperty]  
        public Child Child { get; set; }  
        public SelectList AnotherTableSelectList { get; set; }  //add this...  


        public async Task<IActionResult> OnGetAsync(int? id)  
        {  
            if (id == null)  
            {  
                return NotFound();  
            }  

            Child = await _context.Children  
                .Include(c => c.AnotherTable)  
                .Include(c => c.Parent).FirstOrDefaultAsync(m => m.ChildId == id);  

            if (Child == null)  
            {  
                return NotFound();  
            }  
           ViewData["AnotherTableId"] = new SelectList(_context.AnotherTables, "AnotherTableId", "AnotherTableName");  
           ViewData["ParentId"] = new SelectList(_context.Parents, "ParentId", "ParentName");  
            return Page();  
        }  

        public PartialViewResult OnGetChildPartial(int id)  
        {  

            /*  
                        Child = _context.Children  
                            .Include(c => c.AnotherTable)  
                            .Include(c => c.Parent).FirstOrDefault(m => m.ChildId == id);  

                       ViewData["AnotherTableId"] = new SelectList(_context.AnotherTables, "AnotherTableId", "AnotherTableName");  
                       ViewData["ParentId"] = new SelectList(_context.Parents, "ParentId", "ParentName");  
            */  

            AnotherTableSelectList = new SelectList(_context.AnotherTables, "AnotherTableId", "AnotherTableName");  
            var data = new EditModel(_context);  

            //data.Child = new Child { ChildId = id };  
            data.Child = _context.Children  
                            .Include(c => c.AnotherTable)  
                            .Include(c => c.Parent).FirstOrDefault(m => m.ChildId == id);  

            data.AnotherTableSelectList = AnotherTableSelectList;  

            return Partial("/Pages/Shared/_ChildEdit.cshtml", Child);  
        }  

        // To protect from overposting attacks, enable the specific properties you want to bind to.  
        // For more details, see https://aka.ms/RazorPagesCRUD.  
        public async Task<IActionResult> OnPostAsync()  
        {  
            if (!ModelState.IsValid)  
            {  
                return Page();  
            }  

            _context.Attach(Child).State = EntityState.Modified;  

            try  
            {  
                await _context.SaveChangesAsync();  
            }  
            catch (DbUpdateConcurrencyException)  
            {  
                if (!ChildExists(Child.ChildId))  
                {  
                    return NotFound();  
                }  
                else  
                {  
                    throw;  
                }  
            }  

            return RedirectToPage("./Index");  
        }  

        private bool ChildExists(int id)  
        {  
            return _context.Children.Any(e => e.ChildId == id);  
        }  
    }  
}  

Pages > Shared > _ChildEdit.cshtml

@model TelerikTest.Pages.Childs.EditModel  

@{  
    ViewData["Title"] = "Edit";  
}  

<h1>Create</h1>  

<h4>Child</h4>  
<hr />  
<div class="row">  
    <div class="col-md-4">  
        <form method="post" asp-page-handler="ChildPartial">  
            <input name="IsValid" type="hidden" value="@ViewData.ModelState.IsValid.ToString()" />  
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>  
            <div class="form-group">  
                <label asp-for="Child.ParentId" class="control-label"></label>  
                <input asp-for="Child.ParentId" class="form-control" />  
            </div>  
            <div class="form-group">  
                <label asp-for="Child.ChildName" class="control-label"></label>  
                <input asp-for="Child.ChildName" class="form-control" />  
                <span asp-validation-for="Child.ChildName" class="text-danger"></span>  
            </div>  
            <div class="form-group">  
                <label asp-for="Child.AnotherTableId" class="control-label"></label>  
                <select asp-for="Child.AnotherTableId" class="form-control" asp-items="Model.AnotherTableSelectList"></select>  
            </div>  
            <div class="form-group">  
                <!--<input type="submit" value="Create" class="btn btn-primary" />-->  
            </div>  
        </form>  
    </div>  
</div>  

Models > Child.cs

using System;  
using System.Collections.Generic;  

#nullable disable  

namespace TelerikTest.Models.Scaffold  
{  
    public partial class Child  
    {  
        public int ChildId { get; set; }  
        public int ParentId { get; set; }  
        public string ChildName { get; set; }  
        public int AnotherTableId { get; set; }  

        public virtual AnotherTable AnotherTable { get; set; }  
        public virtual Parent Parent { get; set; }  
    }  
}  

Models > Scaffold > TelerikTestDBContext.cs

using System;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.EntityFrameworkCore.Metadata;  

#nullable disable  

namespace TelerikTest.Models.Scaffold  
{  
    public partial class TelerikTestDBContext : DbContext  
    {  
        public TelerikTestDBContext()  
        {  
        }  

        public TelerikTestDBContext(DbContextOptions<TelerikTestDBContext> options)  
            : base(options)  
        {  
        }  

        public virtual DbSet<AnotherTable> AnotherTables { get; set; }  
        public virtual DbSet<Child> Children { get; set; }  
        public virtual DbSet<OneTable> OneTables { get; set; }  
        public virtual DbSet<Parent> Parents { get; set; }  

        public virtual DbSet<Dashboard> Dashboards { get; set; }  


        protected override void OnModelCreating(ModelBuilder modelBuilder)  
        {  
            modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");  

            modelBuilder.Entity<AnotherTable>(entity =>  
            {  
                entity.ToTable("AnotherTable");  

                entity.Property(e => e.AnotherTableName)  
                    .IsRequired()  
                    .HasMaxLength(50);  
            });  

            modelBuilder.Entity<Child>(entity =>  
            {  
                entity.ToTable("Child");  

                entity.Property(e => e.ChildName)  
                    .IsRequired()  
                    .HasMaxLength(50);  

                entity.HasOne(d => d.AnotherTable)  
                    .WithMany(p => p.Children)  
                    .HasForeignKey(d => d.AnotherTableId)  
                    .OnDelete(DeleteBehavior.ClientSetNull)  
                    .HasConstraintName("FK_Child_AnotherTable");  

                entity.HasOne(d => d.Parent)  
                    .WithMany(p => p.Children)  
                    .HasForeignKey(d => d.ParentId)  
                    .OnDelete(DeleteBehavior.ClientSetNull)  
                    .HasConstraintName("FK_Child_Parent");  
            });  

            modelBuilder.Entity<OneTable>(entity =>  
            {  
                entity.ToTable("OneTable");  

                entity.Property(e => e.Afield).HasMaxLength(50);  
            });  

            modelBuilder.Entity<Parent>(entity =>  
            {  
                entity.ToTable("Parent");  

                entity.Property(e => e.ParentName)  
                    .IsRequired()  
                    .HasMaxLength(50);  
            });  

            modelBuilder.Entity<Dashboard>(entity =>  
            {  
                entity.HasKey(c => new { c.ParentId });  
            });  

            OnModelCreatingPartial(modelBuilder);  
        }  

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);  
    }  
}  
Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
742 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,553 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Tiny Wang-MSFT 2,641 Reputation points Microsoft Vendor
    2021-07-23T06:21:17.437+00:00

    Hi @MaxPowers1982 , I tried to reproduce you issue in my side and I found that it may comes from initializing of AnotherTableSelectList, I'll show my details below:

    Test2.cshtml contains in Shared folder and error appears when my EditModel hasn't set value for menus
    117451-image.png

    Edit.cshtml

    @page  
    @model WebApplication1.Pages.Childs.EditModel  
    @{  
        ViewData["Title"] = "Edit";  
    }  
    <partial name="~/Pages/Shared/Test2.cshtml" />  
    

    Edit.cshtml.cs

    using System.Collections.Generic;  
    using Microsoft.AspNetCore.Mvc;  
    using Microsoft.AspNetCore.Mvc.RazorPages;  
    using WebApplication1.Models;  
      
    namespace WebApplication1.Pages.Childs  
    {  
        public class EditModel : PageModel  
        {  
            public List<Menu> menus { get; set; }  
      
            public IActionResult OnGet(int? id) {  
                return Page();  
            }  
      
        }  
    }  
    

    But if I set default value like this :

    public List<Menu> menus { get; set; } = new List<Menu>  
            {  
                new Menu{ MenuName="m1", MenuId=1 }  
            };  
    

    It worked well. And certainly, it's ok to set value in onGet method like:

    public class EditModel : PageModel  
        {  
            public List<Menu> menus { get; set; }  
      
            public IActionResult OnGet(int? id) {  
                menus = new List<Menu>  
                {  
                    new Menu{ MenuName="m2", MenuId=1 }  
                };  
                return Page();  
            }  
      
        }  
    

    I think you can try my idea in your code, or provide code snippet of Edit.cshtml? I don't know how you call method OnGetChildPartial, at least in my side, I didn't find this method be called as I set debug point in it. Or you may move the method into OnGet ?


    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.
    Best Regards,
    TinyWang

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.