Reputation: 481
I have 4 entities : Vehicle, VehicleBrand, VehicleModel, VehicleVersion
in one-to-many relationship, code-first generated by ef.
Database look like that:
Edit form use jQuery, first dropdown is feeded by a ViewBag, and the other 2 by Json.
And when I save the DropDowns retrn ONLY id ! dooh !
But my Bind expect entity
As you can see vbName came back null and after SaveChanges.. in all entities have name field null
Here is the Controller code for Edit:
[HttpGet]
public async Task<IActionResult> YourEditNewCar(int? id)
{
if (id == null)
{
return NotFound();
}
var brands = await _context.VehicleBrands.OrderBy(b => b.vbName).Select(x => new { Id = x.id, Value = x.vbName }).ToListAsync();
var models = await _context.VehicleModels.OrderBy(m => m.vmName).ToListAsync();
var versions= await _context.VehicleVersions.OrderBy(v =>v.vvName).ToListAsync();
var model = new Vehicle();
ViewBag.BrandList = new SelectList(brands, "Id", "Value");
model = await _context.Vehicles.SingleOrDefaultAsync(m => m.id == id);
if (model == null)
{
return NotFound();
}
return View("~/Views/Manage/YourEditNewCar.cshtml", model);
}
public JsonResult getVehicleModelById(int id)
{
List<VehicleModel> vehicleModelList = new List<VehicleModel>();
vehicleModelList = _context.VehicleModels.Where(m => m.VehicleBrand.id == id).OrderBy(m => m.vmName).ToList(); //.Select(y => new { Id = y.id, Value = y.vmName })
vehicleModelList.Insert(0, new VehicleModel { id = 0, vmName = "Car Model" });
return Json(vehicleModelList);
}
public JsonResult getVehicleVersionById(int id)
{
List<VehicleVersion> vehicleVersionList = new List<VehicleVersion>();
vehicleVersionList = _context.VehicleVersions.Where(m => m.VehicleModel.id == id).OrderBy(m => m.vvName).ToList(); //.Select(y => new { Id = y.id, Value = y.vmName })
vehicleVersionList.Insert(0, new VehicleVersion { id = 0, vvName = "Car Version" });
return Json(vehicleVersionList);
}
and the post:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> YourEditNewCar(int id, [Bind("id,DoorsNr,isAvailable,isDamaged,isDeleted,FabricationDate,FuelTankCapacity,TrunckCapacity,OnBoardKm,SeatNr," +
"LicencePlate, VehicleBrand, VehicleModel, VehicleVersion")] Vehicle vehicle)
{
var user = await _userManager.GetUserAsync(User);
if (ModelState.IsValid)
{
try
{
_context.Update(vehicle);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!VehicleExists(vehicle.id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("YourCar", "Manage");
}
return View(vehicle);
}
in the Edit form dropdowns look like this:
<hr>
<div class="col-md-12 text-center"><h4> Please select :</h4></div>
<div class="row row-list">
<div class="form-group col-xs-4">
<label asp-for="VehicleBrand" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleBrand.id, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", @class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleModel" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleModel.id, new SelectList(string.Empty), "Car Model", new { style = "width: 120px;", @class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleVersion" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleVersion.id, new SelectList(string.Empty), "Car Version", new { style = "width: 110px;", @class = "form-control" })
</div>
</div>
and the scrip from edit form, to feed dropdowns, is like that:
<script>
$(function () {
$("#VehicleBrand_id").change(function () {
//alert("Vehicle Brand dd changed !");
var url = '@Url.Content("~/Manage/getVehicleModelById")';
var ddlsource = "#VehicleBrand_id";
$.getJSON(url, { id: $(ddlsource).val() }, function (data) {
var items = '';
$("#VehicleModel_id").empty();
$.each(data, function (i, row) {
items += "<option value='" + row.id + "'>" + row.vmName + "</option>";
});
$("#VehicleModel_id").html(items);
})
});
});
</script>
All dropdowns works perfect, the return is just id.
And when I SaveChanges, even if I want to save Only in Vehicle table, it update in other entities too, by navigation properties.
_context.Update(vehicle);
await _context.SaveChangesAsync();
I tried this to not Update VehicleBrands, but doesn't have effect :
I feel that I'm missing something simple, or is a wrong approach.
The problem Was in Model! I used Just: public VehicleBrand VehicleBrand { get; set; }
Without declaring field as ForeignKey
I added in model:
[ForeignKey("VehicleVersionid")]
public int VehicleVersionid { get; set; }
Now I added (with Bold) in Model:
[ForeignKey("VehicleBrandid")]
public int VehicleBrandid { get; set; }
public VehicleBrand VehicleBrand { get; set; }
[ForeignKey("VehicleModelid")]
public int VehicleModelid { get; set; }
public VehicleModel VehicleModel { get; set; }
[ForeignKey("VehicleVersionid")]
public int VehicleVersionid { get; set; }
public VehicleVersion VehicleVersion { get; set; }
And edited in :
[HttpPost]
[ValidateAntiForgeryToken]
public async Task YourEditNewCar(int id,[Bind("id,DoorsNr,isAvailable,isDamaged,isDeleted,FabricationDate,FuelTankCapacity,TrunckCapacity,OnBoardKm,SeatNr," +
"LicencePlate, VehicleBrandid, VehicleModelid, VehicleVersionid")] Vehicle vehicle)
Thanks for your patience!:)
Works like a charm ! :)
Upvotes: 1
Views: 322
Reputation: 548
The issue with the code is, mvc modelstate validation processing with respected to the model used in your posted view. So in this your model is vehicles, so with respect vehicle we need to give values for model. vehicleBrand, VehicleModel, VehicleVersion are different model and the value in that field not have any dependencies on Vehicles model at posting time. so in view you need to use like this
<div class="row row-list">
<div class="form-group col-xs-4">
<label asp-for="VehicleBrand" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleBrandid, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", @class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleModel" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleModelid, new SelectList(string.Empty), "Car Model", new { style = "width: 120px;", @class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleVersion" class="control-label hidden" value=""></label>
@Html.DropDownListFor(model => model.VehicleVersionid, new SelectList(string.Empty), "Car Version", new { style = "width: 110px;", @class = "form-control" })
</div>
</div>
and once one model used in view it is will we changed the whole property as entity then it be difficult to manage and check entitystate.unchanged property
Upvotes: 1
Reputation: 258
You should be using
@Html.DropDownListFor(model => model.VehicleBrandid, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", @class = "form-control" })
not
@Html.DropDownListFor(model => model.VehicleBrand.id, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", @class = "form-control" })
Bind your dropdown list to the id field in vehicle entity, not to the id field in the related entity.
Or if you wanted to start using taghelpers in asp.net core you could use this reference: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-select-tag-helper
Upvotes: 1