Why is Data deleted upon getting it back from View - c#

I have a Database where I save Users and Roles, with a many-to-many Relationship. I have those imported via EF Database first as Models. When I try to add, update or remove Roles from a Person, nothing happens, or for example if I press on add, the last Role doesnt show up anymore.
After debugging it a bit. I found out, that after the View gives back the Model (Person) the Roles list is suddenly empty. Why is this and how can I fix it?
This is my Controller Methode to Edit a Person
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return RedirectToAction("BadRequest", "Error", new { area = "" });
}
Person person = await db.Person.FindAsync(id);
if (person == null)
{
return RedirectToAction("NotFound", "Error", new { area = "" });
}
ViewBag.allRoles = db.Roles.ToList();
return View(person);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "id,nachname,vorname,winLogon")] Person person, string command, int? roleId)
{
Role none = new Role { id = -1, name = "None" };
var allRoles = db.Roles.ToList();
if (ModelState.IsValid)
{
if (command != null && command == "remove")
{
person.Roles.Remove(db.Roles.FirstOrDefault(x => x.id == roleId));
return View(person);
}
if (command != null && command == "add")
{
person.Roles.Add(none);
return View(person);
}
if (command != null && command == "save")
{
person.Roles.Remove(none);
db.Entry(userRoles.User).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
return View(person);
}
This is the Person Model
public partial class Person
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Person()
{
this.Roles = new HashSet<Role>();
}
public int id {get;set;}
public string nachname {get;set;}
public string vorname {get;set;}
public string winLogon {get;set;}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Role> Roles {get;set;}
}
And this is the Role Model
public partial class Rolle
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Rolle()
{
this.Person = new HashSet<Person>();
}
public int id { get; set; }
public string name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Person> Person { get; set; }
}
And this is the View
#model Models.Person
#{
ViewBag.Title = "Edit";
List<Role> allRoles = ViewBag.allRoles;
}
<h2>Edit</h2>
#using (Html.BeginForm("Edit", "People", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.id)
<div class="form-group">
#Html.LabelFor(model => model.nachname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.nachname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.nachname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.User.vorname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.vorname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.vorname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.winLogon, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.winLogon, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.winLogon, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group col-md">
#for (int i = 0; i < Model.Roles; i++)
{
#Html.LabelFor(model => model.Roles, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Roles, new SelectList(allRoles, "id", "name", role), new { #class = "form-control-static col-md-1" })
<input type="hidden" name="roleId" value="#role.id" />
<input name="command" type="submit" value="remove" class="btn btn-default col-md-offset-1" />
</div>
}
<input name="command" type="submit" value="add" class="btn btn-default col-md-offset-1" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input name="command" type="submit" value="save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>

Related

ASP.Net MVC Razor DropDownListFor issue

I am fairly new to coding, and am working on a personal MVC project. I am trying to implement a DropDown that uses values submitted by the user. I believe I have almost everything written correctly, but when I go to update an entity, I get the following error:
The ViewData item that has the key 'WrestlerId' is of type 'System.Int32' but must be of type 'IEnumerable'.
Any assistance with this would be appreciated, and I will edit/update to help figure this out.
Edit: The error itself happens in the View on the following line of code:
#Html.DropDownListFor(x => Model.WrestlerId, Model.Wrestlers, htmlAttributes: new { #class = "form-control" })
Model
public class TitleEdit
{
public int TitleId { get; set; }
public string TitleName { get; set; }
[Display (Name = "Favorite")]
public bool IsStarred { get; set; }
[Display(Name ="Date Established")]
public DateTime DateEstablished { get; set; }
[Display(Name = "Current Champion")]
public int? WrestlerId { get; set; }
public string WrestlerName { get; set; }
public IEnumerable<SelectListItem> Wrestlers { get; set; }
}
View
#model Models.TitleCRUD.TitleEdit
#{
ViewBag.Title = "Edit";
}
<h2>Updating Title</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.TitleId)
<div class="form-group">
#Html.LabelFor(model => model.TitleName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TitleName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TitleName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsStarred, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.IsStarred)
#Html.ValidationMessageFor(model => model.IsStarred, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DateEstablished, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateEstablished, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DateEstablished, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WrestlerId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => Model.WrestlerId, Model.Wrestlers, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Wrestlers, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div id="linkColor">
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
//GET: Edit
public ActionResult Edit(int id)
{
var service = CreateTitleService();
var detail = service.GetTitleById(id);
var wrestlerList = new WrestlerRepo();
var model = new TitleEdit
{
TitleId = detail.TitleId,
TitleName = detail.TitleName,
IsStarred = detail.IsStarred,
DateEstablished = detail.DateEstablished,
WrestlerId = detail.WrestlerId
};
model.Wrestlers = wrestlerList.GetWrestlers();
return View(model);
}
//POST: Edit
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, TitleEdit model)
{
if (!ModelState.IsValid)
{
var wrestlerList = new WrestlerRepo();
model.Wrestlers = wrestlerList.GetWrestlers();
return View(model);
}
if (model.TitleId != id)
{
ModelState.AddModelError("", "ID Mismatch");
return View(model);
}
var service = CreateTitleService();
if (service.UpdateTitle(model))
{
TempData["SaveResult"] = "The title has been updated!";
return RedirectToAction("Index");
}
ModelState.AddModelError("", "The title could not be updated.");
return View(model);
}
GetWrestlers()
public IEnumerable<SelectListItem> GetWrestlers()
{
using (var ctx = new ApplicationDbContext())
{
List<SelectListItem> wrestlers = ctx.Wrestlers.AsNoTracking()
.OrderBy(n => n.RingName)
.Select(n =>
new SelectListItem
{
Value = n.WrestlerId.ToString(),
Text = n.RingName
}).ToList();
var wrestlerTip = new SelectListItem()
{
Value = null,
Text = "Select a Wrestler"
};
wrestlers.Insert(0, wrestlerTip);
return new SelectList(wrestlers, "Value", "Text");
}
}

i want to UPDATE Fax table and FaxData table that link between Fax&employees tables

i made viewmodel view to allow me to use the 2 model (Fax&Faxdata) in my view
but i have NULL value of SelectedEmployees in listboxfor
what is the problem in my viewmodel ??
namespace FaxProject.ViewModel
{
public class SendFaxVm
{
public List<SelectListItem> Employees { set; get; }
public int[] SelectedEmployees { set; get; }
public Fax fax { set; get; }
}
}
this is the view (Edite view)
#model FaxProject.ViewModel.SendFaxVm
#using (Html.BeginForm("Edit","Fax"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Fax</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.fax.Id)
<div class="form-group">
#Html.LabelFor(model => model.fax.Courier_Num, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.fax.Courier_Num, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.fax.Courier_Num, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.fax.NumberOfPages, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.fax.NumberOfPages, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.fax.NumberOfPages, "",
<div class="form-group">
#Html.LabelFor(model => model.Employees, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(a => a.SelectedEmployees, Model.Employees)
#Html.ValidationMessageFor(a => a.SelectedEmployees)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Back" class="btn btn-default" />
</div>
</div>
</div>
}
i got null exception in the listbox so how can i get the list of employees of edit it ??
public ActionResult Edit (int id,SendFaxVm vm,Fax fax)
{
var faxindb = Db.Faxes.Single(f=>f.Id==id);
faxindb.Courier_Num = fax.Courier_Num;
faxindb.NumberOfPages = fax.NumberOfPages;
faxindb.CompanyName = fax.CompanyName;
faxindb.ReceivingDate = fax.ReceivingDate;
faxindb.Attachment = fax.Attachment;
faxindb.Subject = fax.Subject;
Db.SaveChanges();
foreach (var userId in vm.SelectedEmployees)
{
var faxdataindb = Db.FaxDatas.Single(f => f.FaxId == fax.Id);
faxdataindb.EmpId = userId;
//to do : Save fd
Db.SaveChanges();
}
return RedirectToAction("FaxForm","Fax");
}
this is the action in Fax controller ...
Hey You can improve couple of things.
public class SendFaxVm
{
public List<SelectListItem> Employees { set; get; }
public List<int> SelectedEmployees { set; get; }
public Fax fax { set; get; }
}
Change array to a List in your Model, You can also use IEnumerable here too. If you , Also follow this example to populate Listbox https://www.codeproject.com/Articles/771999/ASP-Net-MVC-How-to-create-a-ListBox

How To Check Name Already Availability

Here i am trying to check employee name availability while creating the new employee. While Creating the user if the employee name inserted is already available is table it should show already exists and if not it shouls show available message.Here is my Employee model class
[Table("tblEmployee")]
public class Employee
{
public int EmployeeID { get; set; }
[Required(ErrorMessage ="Name Cannot Be Empty")]
public string Name { get; set; }
[Required(ErrorMessage = "Name Cannot Be Empty")]
public string Gender { get; set; }
[Required(ErrorMessage = "Name Cannot Be Empty")]
public string City { get; set; }
}
Below Is Create Method In EmployeeController
[HttpPost]
public ActionResult Create(Employee employee)
{
if (ModelState.IsValid)
{
if (employee.Name!=employee.Name)
{
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
ViewBag.errorMessage = "Name Already Available";
return (ViewBag.errorMessage);
}
}
else
{
return View("Create");
}
}
Below Is Create.cshtml
#model Practise.Models.Employee
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Employee</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
#ViewBag.errorMessage
</div>
<div class="form-group">
#Html.LabelFor(model => model.Gender, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Gender, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Gender, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.City, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.City, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.City, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Your create method should look like
if (ModelState.IsValid)
{
// Check if employee with the same name already exists
var existingEmployee = db.Employees.FirstOrDefault(e => e.Name == employee.Name);
// No
if (existingEmployee == null)
{
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
// Yes
else
{
ViewBag.errorMessage = "Name not available";
return (ViewBag.errorMessage);
}
}
Try using Any() in Linq. Like this:
// This will check if there is an existing name in your database
bool IsEmployeeExist = db.Employees.Any(e => e.Name.Equals(employee.Name));
if(IsEmployeeExist){
// Show Error Message
} else {
// Do insert...
}
Though I think that validating Employee Name is too general as there will be a lot of people who could have the same name.
This line of code doesn't make sense:
employee.Name!=employee.Name
You are attempting to compare the exact same employees name with itself.
Instead, you should search db.Employees by name, with something like:
var doesEployeeExist = db.Employees.Any(e => e.Name == employee.Name);
if "doesEployeeExist" is false, you know the name isn't in use, and you are free to create a new one.
However, you should be aware that it is possible for people to have the same names (first & last), especially as the company grows in size.

Error "A referential integrity constraint violation occurred"

Can you please help me with my code?
I have 2 models:
public class Author
{
public int Id { get; set; }
public string AuthorName { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int YearPublish { get; set; }
public int Price { get; set; }
public int? AuthorId { get; set; } //FK
public Author Author { get; set; } //navigation property
}
And trying to make an Edit function.
Controller code:
// GET: Books/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Book bookEdit = dbBooks.Books.Include(a => a.Author).Where(a => a.AuthorId == id).Single();
return View(bookEdit);
}
// POST: Books/Edit/5
[HttpPost]
public ActionResult Edit(Book book)
{
if (ModelState.IsValid)
{
// TODO: Add update logic here
//book.Author = null; //AuthorName cant be edited
dbBooks.Entry(book).State = EntityState.Modified;
dbBooks.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
And my View:
<div class="form-horizontal">
<h4>Book</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.Author.AuthorName, "AuthorName", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Author.AuthorName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Author.AuthorName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.YearPublish, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.YearPublish, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.YearPublish, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Price, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Price, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
And when i try just to click Save button (even if i dont do any changes) an error occured:
A referential integrity constraint violation occurred: The property value(s) of 'Author.Id' on one end of a relationship do not match the property value(s) of 'Book.AuthorId' on the other end.
Error is in dbBooks.Entry(book).State = EntityState.Modified;
If I try to add book.Author = null; it is logically than my AuthorNames` start to disappear...
Also I was trying to put something in Html.HiddenFor, but maybe I was doing something wrong, but nothing changed.
Well, you couldn't modify AuthorName in Book's editor view. You need another view for Author to modify it.
book.Author - cannot be null, becouse its navigation property and can only be like readonly mode. So just remove editormodel for author.authorname
Modified books list:
Book bookEdit = dbBooks.Books.ToList().Where(a => a.Id == id).SingleOrDefault();
Look what you need to do, i got it now. You just need selectList of all Author's and in a view name will be auto selected on AuthorId book's field.
Make new one form-group with
<div class="form-group">
#Html.LabelFor(model => model.AuthorId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#(Html.DropDownListFor(p => p.AuthorId, (SelectList)ViewBag.Authors, new { #class = "form-control" }))
#Html.ValidationMessageFor(model => model.AuthorId, "", new { #class = "text-danger" })
</div>
</div>
And in Your Edit action:
// GET: Books/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Book bookEdit = dbBooks.Books.Where(a => a.Id == id).Single();
// UPDATED
var list = dbBooks.Books.Select(x => new { ID = x.Id, AuthorName = x.AuthorName });
ViewBag.Authors = new SelectList(list, "Id", "AuthorName");
// UPDATED
return View(bookEdit);
}
Again many thanks!
But using DropDownList dont allow me to edit Author`s name.. But that solution is rly good.
I need to edit all 4 fields like name, title, year and price.
I try to make something like composite model:
public class BookAuthorCompositeModel
{
public Author author { get; set; }
public Book book { get; set; }
}
Change my get method:
// GET: Books/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return HttpNotFound();
}
var compModel = new BookAuthorCompositeModel();
compModel.book = dbBooks.Books.ToList().Where(a => a.Id == id).SingleOrDefault();
compModel.author = dbBooks.Authors.ToList().Where(x => x.Id == id).SingleOrDefault();
return View(bookEdit);
}
and it displays all I need (i tap "edit" and see information about name, title, year and price).
My view is:
#model BookStorage.Models.BookAuthorCompositeModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Book</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.book.Id)
<div class="form-group">
#Html.LabelFor(model => model.author.AuthorName, "AuthorName", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.author.AuthorName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.author.AuthorName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.book.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.book.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.book.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.book.YearPublish, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.book.YearPublish, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.book.YearPublish, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.book.Price, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.book.Price, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.book.Price, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
but something wrong is in Post method:
[HttpPost]
public ActionResult Edit(Book book)
{
if (ModelState.IsValid)
{
dbBooks.Entry(BAmodel.book).State = EntityState.Modified;
dbBooks.Entry(BAmodel.author).State = EntityState.Modified;
dbBooks.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
dbBooks.SaveChanges(); leads to error..
I think using this kind of ViewModel helps to edit all rows, but it doesnt sade data to DB...
Maybe you could help with this please?

FluentValidation RuleFor attribute of Foreign Key

When I run the program I get a System.NullReferenceException on x.Album.Title == "Disintegration" in:
RuleFor(x => x.Contents)
.NotNull()
.When(x => x.Album.Title == "Disintegration");
How can I program this so that Contents is not accepted as Null when Album.Title == "Disintegration?
Model
[Validator(typeof(ReviewValidation))]
public class Review
{
public int ReviewID { get; set; }
[Display(Name = "Album")]
public int AlbumID { get; set; }
public virtual Album Album { get; set; }
public string Contents { get; set; }
[DataType(DataType.EmailAddress)]
public string ReviewerEmail { get; set; }
}
Validation
public class ReviewValidation : AbstractValidator<Review>
{
public ReviewValidation()
{
RuleFor(x => x.Contents)
.NotNull()
.When(x => x.Album.Title == "Disintegration");
}
}
Controller
public class ReviewsController : Controller
{
private StoreContext db = new StoreContext();
public ActionResult Create()
{
ViewBag.AlbumID = new SelectList(db.Albums, "AlbumID", "Title");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Review review)
{
if (ModelState.IsValid)
{
db.Reviews.Add(review);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AlbumID = new SelectList(db.Albums, "AlbumID", "Title", review.AlbumID);
return View(review);
}
}
View
#model MVCMusicStore.Models.Review
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Review</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.AlbumID, "AlbumID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("AlbumID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.AlbumID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Contents, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Contents, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Contents, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ReviewerEmail, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ReviewerEmail, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ReviewerEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Your view needs to pass the Album.Title back to the POST action in order to validate it. At the moment (from the code you posted), the Album property is null since it was never assigned an actual album, then in the view code where you post to the action, you didn't include the title.
Anyway, the exception you are getting is because Album prop is null in your code, and you are trying to validate its title.
What you could do also is to change the validation code, to only validate when album is not null
When(x => x.Album != null, () =>
{
RuleFor(x => x.Contents).NotNull().When(x => x.Album.Title == "Disintegration");
});

Categories

Resources