FluentValidation RuleFor attribute of Foreign Key - c#

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");
});

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");
}
}

ASP.NET MVC POST won't send back second ocurrence of variable

The class Unidade:
public class Unidade
{
public int UnidadeId { get; set; }
public string Apelido { get; set; }
public string Descricao { get; set; }
}
Is used twice in the class Insumo, as Unidade and UnidadeConsumo
public class Insumo
{
public int InsumoId { get; set; }
public string Apelido { get; set; }
public string Descricao { get; set; }
public int UnidadeId { get; set; }
public Unidade Unidade { get; set; }
public int UnidadeConsumoId { get; set; }
public Unidade UnidadeConsumo { get; set; }
}
To edit Insumo there are two actions EDIT in the controller:
public ActionResult Edit(int? id)
{
Insumo insumo = db.Insumos.Find(id);
if (insumo == null) return HttpNotFound();
ViewBag.UnddId = new SelectList(db.Unidades, "UnidadeId", "Apelido", insumo.UnidadeId);
ViewBag.UndConsId = new SelectList(db.Unidades, "UnidadeId", "Apelido", insumo.UnidadeConsumoId);
return View(insumo);
}
And the POST EDIT:
[HttpPost]
public ActionResult Edit([Bind(Include = "InsumoId,Apelido,Descricao,UnidadeId,UnidadeConsumoId")] Insumo insumo)
{
if (ModelState.IsValid)
{
db.Entry(insumo).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.UnddId = new SelectList(db.Unidades, "UnidadeId", "Apelido", insumo.UnidadeId);
ViewBag.UndConsId = new SelectList(db.Unidades, "UnidadeId", "Apelido", insumo.UnidadeConsumoId);
return View(insumo);
}
The view to display the fields to edition, comprised of two dropdown lists to select both units is:
#model Gestor.Models.Insumo
#{
ViewBag.Title = "Alterar";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Alterar</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Insumo</h4>
<hr />
#Html.Partial("CopyEdit")
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Gravar" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Retornar a lista", "Index")
</div>
And the partial view CopyEdit in the center:
#model Gestor.Models.Insumo
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.InsumoId)
<div class="form-group">
#Html.LabelFor(model => model.Apelido, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Apelido, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Apelido, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Descricao, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Descricao, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Descricao, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UnidadeId, "Unidade", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("UnddId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.UnidadeId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UnidadeConsumoId, "Unidade de Consumo", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("UndConsId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.UnidadeConsumoId, "", new { #class = "text-danger" })
</div>
</div>
The problem is thta whrn returned to the POST Edit action, all fields are ok, but UnidadeConsumoId is always 0, what doesn't even exists in the database?
Can someone tell me why is it not returning the expected value, i.e. the selected value in the dropdown list reflecting the id of if?
Because your current code is rendering a SELECT element with name attribute value UndConsId.
<select class="form-control" name="UndConsId">
<!-- options -->
</select>
For model binding to work, the input element name attribute value should match with the parameter/property name used in the http post action method. Your parameter name is UnidadeConsumoId, not UndConsId
To fix this issue, pass UnidadeConsumoId as the first parameter of the DropDownList method call so that it will render the SELECT element with name UnidadeConsumoId. You can pass the ViewBag.UndConsId as the second parameter to explicitly specify the collection to be used to build the SELECT element.
This should work
#Html.DropDownList("UnidadeConsumoId", ViewBag.UndConsId as SelectList,
new { #class = "form-control" })

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

Form values not being passed to controller

My Controller Method:
[HttpGet]
public ActionResult NewInventory()
{
return View();
}
[HttpPost]
public async Task<ActionResult> NewInventory(string bookID, string ttlin, string lowin, string Outnow)
{
// test values passed, etc.....
}
So far only the "lowin" value is being passed correctly. All the other values are set to "0" (I believe due to the datatypes being set to "not null" in SQL DB). Why is this?
I assume because only one value is passed correctly and no exceptions are thrown, then the view page code is missing the other the fields to pass.
View Code :
#model LibraryMS.Inventory
#{
ViewBag.Title = "newinventory";
}
<h2>newinventory</h2>
#using (Html.BeginForm("NewInventory","BookInfo", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Inventory</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.BookID, "BookID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BookID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BookID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TotalIn, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TotalIn, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TotalIn, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LowIn, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LowIn, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LowIn, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Out, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Out, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Out, "", 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>
By looking, the values are being passed.
Turns out that the controller method's parameters needs to be spelled the same as what is going to be passed to it. For example:
With the autogenerated form using html helper #Beginform, all the fields are present. But the parameters in the controller method are not the same as the inventory's class fields.
public partial class Inventory
{
public string BookID { get; set; }
public short TotalIn { get; set; }
public short LowIn { get; set; }
public short Out { get; set; }
public virtual BookInfo BookInfo { get; set; }
}
Compared to the paramters:
[HttpPost]
public async Task<ActionResult> NewInventory(string bookID, string ttlin, string lowin, string Outnow)
{
// test values passed, etc.....
}
The fix was to ofcoarse make the params the same, capitalization does not matter.
[HttpPost]
public async Task<ActionResult> NewInventory(string bookID, string totalin, string lowin, string Out)
{
// test values passed, etc.....
}
It was a simple mistake but took me some time to figure this out. Hopefully this helped someone else!

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?

Categories

Resources