many to many relationship update data mvc .net core - c#

I have a many to many relationship in .net core mvc, but I have no idea how to implement a edit view.
The models are
Studios
public class Studio
{
public int StudioID { get; set; }
public string Name { get; set; }
public ICollection<StudioAddress>StudioAddresses { get; set; }
}
Addresses
public class Address
{
public int AddressID { get; set; }
public string Street { get; set; }
public ICollection<StudioAddress> StudioAddresses { get; set; }
}
StudioAddress
public class StudioAddress
{
public int StudioID { get; set; }
public Studio Studio { get; set; }
public int? AddressID { get; set; }
public Address Address { get; set; }
}
My databasecontext
modelBuilder.Entity<StudioAddress>()
.HasKey(sa => new { sa.StudioID, sa.AddressID });
modelBuilder.Entity<StudioAddress>()
.HasOne(sa => sa.Studio)
.WithMany(s => s.StudioAddresses)
.HasForeignKey(sa => sa.StudioID);
modelBuilder.Entity<StudioAddress>()
.HasOne(sa => sa.Address)
.WithMany(a => a.StudioAddresses)
.HasForeignKey(sa => sa.AddressID);
Now, I have created the edit Get method in my studioscontroller
// get
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var studio = await _context.Studios
.Include(s => s.StudioAddresses).ThenInclude(s => s.Address)
.Where(s => s.StudioID == id)
.AsNoTracking()
.FirstOrDefaultAsync();
if (studio == null)
{
return NotFound();
}
return View(studio);
}
But I have no idea how to update the related data for studio and address?
Bot are forms with textfields. The original microsoft docs are confusing (they work with tickboxes) and weird methods to whitelist fields. Is there a simpler, more intuitive way of doing this?

Based on your model definition, you could try to design the Edit view and the Post method like below :
Here is the “Edit” view:
#model SOMVCDemo.Models.Studio
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="StudioID" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">StudioAddresses</label>
<table>
<tbody>
#{ int i = 0;}
<tr>
#foreach (var StudioAddress in #Model.StudioAddresses)
{
<td>
<input type="hidden" name="studioAddresses[#i].AddressID" asp-for="#StudioAddress.AddressID" class="form-control" />
<input type="text" name="studioAddresses[#i].Address.Street" asp-for="#StudioAddress.Address.Street" class="form-control" />
</td>
i++;
}
</tr>
</tbody>
</table>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
Here is the POST method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Studio studio)
{
if (id != studio.StudioID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
var st = _context.Studios.FirstOrDefault(n => n.StudioID == studio.StudioID);
st.Name = studio.Name;
_context.Update(st);
foreach(var i in studio.StudioAddresses)
{
var address = _context.Addresses.FirstOrDefault(n=>n.AddressID == i.AddressID);
address.Street = i.Address.Street;
_context.Update(address);
}
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!StudioExists(studio.StudioID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(studio);
}

Related

How to Get Selected List of DropDownList from Database or Model and Populate in Dropdown on View

I am performing a Bitwise-Create operation on my modal(view) and I am to select a dropdown list of users from another table/model and bind to the view so I can forward the request to them. I want to select users based on a certain role, if possible: but I just want to select the users from the database table.
If you need any other model or controller, kindly prompt me so i add it.
Please help..
Below is my Code:
Cshtml Code for the Modal View:(Removed Other TextFields):
So where I have the select tags, i want to get the select list of users and add it.
<div class="row">
<div class="col-md-12">
<form asp-action="AddOrEdit" asp-route-id="#Model.BitwiseId" autocomplete="false" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="AccountName" class="control-label"></label>
<input asp-for="AccountName" class="form-control" />
<span asp-validation-for="AccountName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="File" class="control-label"></label>
<input type="file" name="userfile" class="form-control" accept=".xlsx"/>
<span asp-validation-for="File" class="text-danger"></span>
</div>
<div class="form-group">
<label for="cars">Select 1st Approver </label>
<select name="group_heads" id="group_heads" class="form-control">
<option value="">Select</option>
<option value="2">Bobby</option>
</select>
</div>
<hr />
<div class="d-grid gap-2">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
Code: Controller for the Bitwise - Add Method:
namespace BOGBitwiseApp.Controllers
{
public class BitwiseController : Controller
{
private readonly ApplicationDbContext _context;
public BitwiseController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
return View(await _context.Bitwises.ToListAsync());
}
// GET: Transaction/AddOrEdit(Insert)
// GET: Transaction/AddOrEdit/5(Update)
[NoDirectAccess]
public async Task<IActionResult> AddOrEdit(int id = 0)
{
if (id == 0)
return View(new BitwiseModel());
else
{
var bitwiseModel = await _context.Bitwises.FindAsync(id);
if (bitwiseModel == null)
{
return NotFound();
}
return View(bitwiseModel);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrEdit(int id, [Bind("BitwiseId,..., Amount")] BitwiseModel bitwiseModel, ...)
{
if (ModelState.IsValid)
{
//New
if (id == 0)
{
string filename = userfile.FileName;
...
await userfile.CopyToAsync(stream);
var data = _context.Users.ToListAsync();
bitwiseModel.Date = DateTime.Now;
_context.Add(bitwiseModel);
await _context.SaveChangesAsync();
}
//Update
else
{
try
{
_context.Update(bitwiseModel);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BitwiseModelExists(bitwiseModel.BitwiseId))
{ return NotFound(); }
else
{ throw; }
}
}
return Json(new { isValid = true, html = Helper.RenderRazorViewToString(this, "_ViewAll", _context.Bitwises.ToList()) });
}
return Json(new { isValid = false, html = Helper.RenderRazorViewToString(this, "AddOrEdit", bitwiseModel) });
}
Model Code for Bitwise (Add):
public class BitwiseModel
{
[Key]
public int BitwiseId { get; set; }
[Required]
[Column(TypeName = "nvarchar(100)")]
[DisplayName("Customer Name")]
public string AccountName { get; set; }
[NotMapped]
[DisplayName("Invoice File")]
public IFormFile? File { get; set; }
}
**Model for Users Table:**
public class ApplicationUser : IdentityUser
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public int UsernameChangeLimit { get; set; } = 2;
public byte[]? ProfilePicture { get; set; }
}

How can I solve the problem with Models in ASP.NET.MVC?

I have a problem. I have posts on the wall. And if the user has entered the site, then he can send his response to the post. How do I make it so that when using my TakeAnswer method, I can create a new row in the database? Now I only save the user's response, but not the ID of the post to which he replied.
[HttpGet]
public IActionResult Index()
{
var posts = db.Posts.ToList();
if (posts == null)
return View();
var temp = new IndexModel();
temp.Posts = posts;
temp.PostID = 0;
temp.IndexAnswer = "";
return View(temp);
}
[HttpPost]
public async Task<IActionResult> TakeAnswer(IndexModel model, string PostID)
{
if (ModelState.IsValid)
{
db.Answers.Add(new Answer { UserId = GetUserId, UserAnswer = model.IndexAnswer, PostId = int.Parse(PostID) });
await db.SaveChangesAsync();
}
return View();
}
public class IndexModel
{
[BindProperty]
public string IndexAnswer { get; set; }
[BindProperty]
public int PostID { get; set; }
public IEnumerable<Post> Posts { get; set; }
}
#model CourseProject.ViewModels.IndexModel
<form asp-action="TakeAnswer" asp-controller="Home">
#if (Model != null)
{
#foreach (var post in Model.Posts)
{
<div class="card my-3">
<h5 class="card-header font-weight-bold">
#Html.DisplayFor(model => post.PostName)
</h5>
<div class="card-body">
<p class="card-text">#Html.DisplayFor(model => post.PostContent)</p>
#if (User.Identity.IsAuthenticated)
{
<div class="form-group">
<label asp-for="IndexAnswer">Your answer to this problem</label><br />
<input type="text" asp-for="IndexAnswer" />
</div>
<div>
<button type="submit" class="btn btn-primary" asp-route-PostID="#post.Id">Reply</button>
</div>
}
</div>
<div class="card-footer">
<p>Task created: #Html.DisplayFor(model => post.Date)</p>
</div>
</div>
}
}
</form>

Display data from a drop down in the view asp.net core

I have a view that needs to display a drop-down and then displaying data from the drop-down in the same view using viewBag
There is 3 tables customer, assign, employee. Assign and employee have a relationship but the customer does not and is not needed so ViewBag is being used to display data in another view, how I build a drop-down list displayed in the view using the viewBag and display the selected data from the customer table in the same view?
The view that the data is needed to be displayed in mainly the name, task, and image from the URL
#model HandyApp.Models.ViewModels.AsignVM
<div>
// drop down needed in this section
</div>
<div>
// display data from selected drop down item needed in this section
</div>
<form method="post" asp-action="Create">
<div class="container">
<div class="form-row">
<div class="col-md-12">
<h1>Customer task</h1>
</div>
</div>
<div class="form-row">
<div class="col-md-12"><strong style="margin-right: 7px;">Name :</strong><span style="margin-top: 1px;">harry</span></div>
</div>
</div>
<div class="container">
<div class="form-row">
<div class="col-md-12"><strong>Tasks :</strong><span style="margin-left: 12px;">paint shed</span></div>
</div>
</div>
<div class="container">
<div class="form-row">
<div class="col-md-12"><strong>Telephone number :</strong><span style="margin-left: 12px;">000000000000</span></div>
</div>
</div>
<div class="container">
<div class="form-row">
<div class="col"><strong>Address : </strong><span>123 Fake Street</span><span></span></div>
<div class="col-md-12" style="margin-top: 31px;">
<h3 style="margin-left: 0px;">Assign tasks</h3>
</div>
</div>
<div class="form-row">
<div class="col-md-3">
<label style="margin-left: 47px;">Name of customer</label>
<input asp-for="Asign.Name" class="form-control" type="text" value="customers name" style="margin-top: 2px;">
<label style="margin-top: 8px;">Employee Assign </label>
<select asp-for="Asign.EmployeeNameId" asp-items="#Model.TypeDropDown" class="form-control">
<option selected>-- Select option</option>
</select>
<label style="margin-top: 8px;">Employee Assign </label>
<select asp-for="Asign.Status" class="form-control">
<option value="in progress" selected="">in progress</option>
<option value="completed">completed</option>
</select>
</div>
<div class="col-md-3">
<label style="margin-left: 54px;">Tasks </label>
<input asp-for="Asign.Tasks" class="form-control" value="Enter tasks here" style="margin-top: 4px;">
<label style="margin-top: 8px;">Telephone</label>
<input asp-for="Asign.Telephone" value="Type telephone" class="form-control" type="text">
<label tyle="margin-top: 8px;">Address</label>
<input asp-for="Asign.Address" class="form-control" value="enter address" type="text"></div>
</div>
<button class="btn btn-primary" type="submit" style="margin-top: 35px;margin-left: 34px;">Submit</button>
</div>
</form>
Customer model
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Tasks { get; set; }
public string Telephone { get; set; }
public string Address { get; set; }
public string ImageUrl { get; set; }
}
Assign model
public class Assign
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Tasks { get; set; }
public string Telephone { get; set; }
public string Address { get; set; }
public string Status { get; set; }
public string ImageUrl { get; set; }
public int EmployeeNameId { get; set; }
[ForeignKey("EmployeeNameId")]
public virtual Employee Employee { get; set; }
}
Employee model
public class Employee
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Speciality { get; set; }
}
Assign ViewModel
public class AssignVM
{
public Assign Assign { get; set; }
public IEnumerable<SelectListItem> TypeDropDown { get; set; }
}
Assign controller
public class AssignController : Controller
{
private readonly ApplicationDbContext _db;
public AssignController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Asign> objList = _db.Assigns;
IEnumerable<Customer> custObj = _db.Customers;
foreach (var obj in objList)
{
obj.Employee = _db.Employees.FirstOrDefault(u => u.Id == obj.EmployeeNameId);
}
ViewBag.Customer = custObj;
return View(objList);
}
public IActionResult Create()
{
AssignVM assignVM = new AssignVM()
{
Assign = new Assign(),
TypeDropDown = _db.Employees.Select(i => new SelectListItem
{
Text = i.Name,
Value = i.Id.ToString()
})
};
return View(assignVM);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(AssignVM obj)
{
_db.Assigns.Add(obj.Assign);
_db.SaveChanges();
return RedirectToAction("Index");
}
public IActionResult Delete(int? id)
{
if (id == null || id == 0)
{
return NotFound();
}
var obj = _db.Assigns.Find(id);
if (obj == null)
{
return NotFound();
}
return View(obj);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult DeletePost(int? id)
{
var obj = _db.Assigns.Find(id);
if (obj == null)
{
return NotFound();
}
_db.Assigns.Remove(obj);
_db.SaveChanges();
return RedirectToAction("Index");
}
}
Use a jquery to get data from controller will be the easiest way, you can check my demo:
The image is stored in wwwroot/Images/*** in my demo.
Controller:
[HttpGet]
public JsonResult GetCustomer(string Id)
{
var img = _db.Customers.Where(x => x.Id.ToString()==Id).ToList();
return Json(img);
}
View:
<div>
<select class="form-control" id="select1" asp-items="#(new SelectList(ViewBag.customers,"Value", "Text"))">
</select>
</div>
<div id="showhere">
</div>
//........your other html
#section Scripts
{
<script>
$(document).ready(function () {
$("#select1").change(function () {
var Id = $("#select1 option:selected").val();
$.ajax({
type: 'Get',
url: 'Assign/GetCustomer',
data: { Id: Id },
dataType: "json",
success: function (data) {
document.getElementById("showhere").innerHTML = "";
document.getElementById("showhere").innerHTML +=
"<img src=" + data[0].imageUrl + " height="+50+" width="+50+">";
}
});
});
});
</script>
}
Result:

Error using TryUpdateModelAsync in a form with navigation properties

Suppose I have a form that contains the following model structure:
TestRecord.cs
class TestRecord {
public string Id { get; set; }
public string RecordName { get; set; }
...other props
public ICollection<RtdbFiles> RtdbFiles { get; set; }
}
Where the corresponding RtdbFile contains the following props:
RtdbFile.cs
class RtdbFile {
public int Id { get; set; }
public string Filename { get; set; }
...other props
}
When I POST this model to my controller to update, I receive the following error:
The instance of entity type 'RtdbFile' cannot be tracked because another instance with the key value '{Id: 2021}' is already being tracked
So it appears that two of the same RtdbFile are being attached to the context. Here's how my controller method is formatted:
[HttpPost("UpdateMilestones")]
public async Task<IActionResult> UpdateMilestones(string testRecordId)
{
db.ChangeTracker.LazyLoadingEnabled = false;
var record = db.TestRecords
.Include(tr => tr.RtdbFiles)
.FirstOrDefault(tr => tr.TestRecordId == testRecordId);
if (await TryUpdateModelAsync(record))
{
await db.SaveChangesAsync();
}
return RedirectToAction("Milestones", new { id = testRecordId });
}
Is TryUpdateModelAsync() not made to handle situations with a One-to-Many relationship? When is the duplicate RtdbFile being added to the context? I've disabled lazy loading and eagerly load the RtdbFiles. This is similar to what is done in the Contoso University example by Microsoft but the difference is their eagerly loaded property is a One-to-One relationship.
How can I fix this? Thanks!
EDIT to show Razor Pages:
UpdateMilestones.cshtml
#model rtdb.Models.TestRecord
#addTagHelper *, rtdb
<input type="hidden" asp-for="#Model.TestRecordId" />
<div class="form-section-text">Milestones & Tracking</div>
<!--unrelated inputs removed -->
<div class="form-group">
<vc:file record="#Model" type="#RtdbFile.AttachmentType.TPR" approvers="true"></vc:file>
</div>
The RtdbFiles are abstracted out a bit in to view components:
File View Component
#model rtdb.Models.ViewModels.FileViewModel
#addTagHelper *, rtdb
#using HtmlHelpers.BeginCollectionItemCore
<div class="form-group attachments">
<div class="link-header">#(Model.AttachmentType.ToString("G"))</div>
<div class="row">
<div class="col-sm-12">
#if (Model.TestRecord.RtdbFiles.Count > 0)
{
foreach (var file in Model.TestRecord.RtdbFiles.Where(f => f.IsDeleted != true && f.Type == Model.AttachmentType && f.TestRecordId == Model.TestRecord.TestRecordId).ToList())
{
<div class="attachment">
#using (Html.BeginCollectionItem("RtdbFiles"))
{
<div class="form-group">
<div class="form-row">
<input asp-for="#file.Id" hidden />
<input asp-for="#file.Type" hidden />
<div class="col-sm-6">
#if (#file.Id < 1)
{
<input class="FileInput" asp-for="#file.UploadedFile" type="file" />
}
else
{
<div><span data-file-id="#file.Id"><a href='#Url.Action("Download", "RtdbFiles", new { id = file.Id })'>#file.Filename (#file.Type.ToString("G"))</a></span></div>
}
</div>
<div class="col-sm-6">
<div>
<label asp-for="#file.FileApproverPersonnel" class="col-form-label col-form-label-sm">Approvers:</label>
<input asp-for="#file.FileApproverPersonnel" class="form-control file-approver-personnel ldap-tags" />
</div>
</div>
</div>
</div>
}
</div>
}
}
<div id="#(Model.AttachmentType.ToString("G"))s"></div>
<button type="button" class="add-file btn btn-primary" data-test-type="Other" data-attachment-type="TPR" data-container="#(Model.AttachmentType.ToString("G"))s">Add #(Model.AttachmentType.ToString("G"))</button>
<small style="display: block; margin-top: 6px">File size limit: 100MB</small>
</div>
</div>
</div>
What is obvious is TryUpdateModelAsync or maybe ChangeTracker has some issues with string ForeignKeys. First of all I highly recommend you to change PrimaryKey to int because EF shows some odd behaviour in such cases.
But if you insist on it, I tried some ways and finally reach this way:
Preventing object from tracking with AsNoTracking and use context.Update after updating record based on controller model
Based on your latest models, It's my sample that works well:
Models:
public class TestRecord
{
public string Id { get; set; }
public string RecordName { get; set; }
public virtual IList<RtdbFile> RtdbFiles { get; set; }
}
public class RtdbFile
{
public int Id { get; set; }
public string TestRecordId { get; set; }
public string Filename { get; set; }
}
Razor Page:
Note: This part has the most important effect on your result. specially RtdbFiles[{i}].Id and RtdbFiles[{i}].Filename
Your View have to send items and values with exactly same name to server object to take effect correctly:
#model Jordan.TestRecord
#using (Html.BeginForm("UpdateMilestones", "Home", FormMethod.Post))
{
#Html.HiddenFor(p => p.Id);
#for (int i = 0; i < Model.RtdbFiles.Count; i++)
{
#Html.Hidden($"RtdbFiles[{i}].Id", Model.RtdbFiles[i].Id);
#Html.TextBox($"RtdbFiles[{i}].Filename", Model.RtdbFiles[i].Filename);
}
<button type="submit">Save</button>
}
Controller:
namespace Jordan
{
[Route("")]
public class HomeController : Controller
{
private readonly AppDbContext context;
public HomeController(AppDbContext context)
{
this.context = context;
context.Database.EnsureCreated();
}
[HttpGet]
public IActionResult Index()
{
var sampleRecord = context.TestRecords
.Include(r => r.RtdbFiles)
.FirstOrDefault();
return View(sampleRecord);
}
[HttpPost]
[Route("UpdateMilestones")]
public async Task<IActionResult> UpdateMilestones(int Id)
{
context.ChangeTracker.LazyLoadingEnabled = false;
var record = context.TestRecords
.Include(tr => tr.RtdbFiles)
.AsNoTracking()
.FirstOrDefault(tr => tr.Id == Id);
if (await TryUpdateModelAsync(record))
{
context.Update(record);
await context.SaveChangesAsync();
}
return RedirectToAction("Index");
}
}
}
I got it, but there seems to be no case of TryUpdateModelAsync on
one-to-many online. (And I tried without success).
Therefore, I suggest that you can use our common method of updating the one-to-many data model.
In the view, you need to bind each field of TestRecord to the corresponding control and pass the latest data of TestRecord to UpdateMilestones action.
Please refer to the following code:
View (which show one record of TestRecord and it related to multiple RtdbFiles datas):
#model WebApplication_core_mvc.Controllers.TestRecord
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
var i = 0;
}
<h1>Index</h1>
<form asp-action="UpdateMilestones" method="post">
<input id="Text1" type="text" asp-for="Id" hidden />
<label>#Model.Id</label>
<input id="Text2" type="text" asp-for="RecordName" />
<br />
<h4>Rtb:</h4>
<table>
<tr>
<th>Id</th>
<th>FileName</th>
</tr>
#foreach (var item in Model.RtdbFiles)
{
<tr>
<td> <input id="Text1" type="text" value="#item.Id" name="RtdbFiles[#i].Id" hidden/>#item.Id</td>
<td> <input id="Text1" type="text" value="#item.Filename" name="RtdbFiles[#i].Filename" /></td>
</tr>
i++;
}
</table>
<input id="Submit1" type="submit" value="submit" />
</form>
Update
Controller:
[HttpPost("UpdateMilestones")]
public async Task<IActionResult> UpdateMilestones(TestRecord testRecord)
{
db.Entry(testRecord).State = EntityState.Modified;
db.Entry(testRecord).Property(x => x.Id).IsModified = false;
foreach (var item in testRecord.RtdbFiles)
{
db.Entry(item).State = EntityState.Modified;
db.Entry(item).Property(x => x.Id).IsModified = false;
}
await db.SaveChangesAsync();
return RedirectToAction("Milestones", new { id = testRecord.Id });
}
Here is the test result:

Can’t update ICollection property

The problem is when I try to update Master and Details Tables at the same time.
When call Post Edit Task the Details objects don´t appear.
The Edit View displays all Details rows correctly, but while debugging the Edit POST, Casas is empty
MODELS
public partial class Modelo : IValidatableObject {
public Modelo()
{
Casas = new HashSet<Casa>();
}
public int Modeloid { get; set; }
public string Modelo1 { get; set; }
public virtual ICollection<Casa> Casas { get; set; }//Don’t work to update
}
public partial class Casa // DETAIL TABLE
{
public int Casaid { get; set; }
public int Modeloid { get; set; } // FK to Modelo
public string Casa1 { get; set; }
public virtual Modelo Modelo { get; set; }
}
CONTROLLER
public class ModelosController : Controller
. . . . . . . . .
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Modelo modelo)
{
if (id != modelo.Modeloid)
{
return NotFound();
}
if (ModelState.IsValid)
{
// Here modelo.Modelo1 has current modified value
// but modelo.Casas.Count == 0
_context.Update(modelo);
await _context.SaveChangesAsync();
}
}
// GET: Modelos/Edit
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var modelo = await _context.Modelo
.AsNoTracking()
.Include(m => m.Fotomodelos)
.Include(m => m.Casas)
.SingleOrDefaultAsync(m => m.Modeloid == id);
if (modelo == null)
{
return NotFound();
}
return View(modelo);
}
View EDIT.CSHTML
#using System.IO
#model Disponibilidad.Models.Modelo
<form asp-action="Edit">
<div class="form-horizontal">
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Modeloid" />
<div class="form-group">
<label asp-for="Modelo1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Modelo1" class="form-control" />
<span asp-validation-for="Modelo1" class="text-danger"></span>
</div>
</div>
#{
for (int i = 0; i < Model.Casas.Count; i++)
{
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Modeloid"
value="#Model.Modeloid" />
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Casaid" />
<div class="form-group">
<label asp-for="#Model.Casas.ElementAt(i).Casa1"
class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="#Model.Casas.ElementAt(i).Casa1"
class="form-control" /> <!-- DISPLAY OK Detail rows -->
<span asp-validation-for="#Model.Casas.ElementAt(i).Casa1"
class="text-danger"></span>
</div>
</div>
}
}
<div class="btn-group">
<button type="submit" class="btn btn-danger">Save</button>
</div>
</div>
</form>
When you use a for cycle instead of foreach in Razor, the name of the properties doesn't get rendered correctly when using the default asp-for TagHelpers.
You can correct your example changing your razor form inputs as follow:
From:
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Casaid" />
To:
<input type="hidden" name="modelo.Casas[#i].Casaid" value="#Model.Casas.ElementAt(i).Casaid" />

Categories

Resources