Combined Multiple Models into Single View - Create Problem - entity-framework

I'm trying to combine the Address and Country Create Views into a single view. I'm using MVC 3 with Repository Scaffolding & ASPX Views. I currently have a Country drop-down list that is already populated, and am trying to add this to the Address Create View. I have the Edit View working just fine. However when I try to create a new Address it adds a new Country with a blank name even though I choose a Country in the drop down list. I feel like I'm missing something very fundamental because this should be easy.
POCO Classes
public class Address
{
public int ID { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
[ForeignKey("Country")]
public int CountryID { get; set; }
public Country Country { get; set; }
}
public class Country
{
public int ID { get; set; }
[Display(Name = "Country"), MaxLength(50)]
public string Name { get; set; }
}
Address Controller
public class AddressController : Controller
{
private readonly IAddressRepository addressRepository;
private readonly ICountryRepository countryRepository;
// If you are using Dependency Injection, you can delete the following constructor
public AddressController() : this(new AddressRepository(), new CountryRepository())
{
}
public AddressController(IAddressRepository addressRepository, ICountryRepository countryRepository)
{
this.addressRepository = addressRepository;
this.countryRepository = countryRepository;
}
//
// GET: /Address/
public ViewResult Index()
{
return View(addressRepository.All);
}
//
// GET: /Address/Details/5
public ViewResult Details(int id)
{
return View(addressRepository.Find(id));
}
//
// GET: /Address/Create
public ActionResult Create()
{
ViewBag.PossibleCountries = countryRepository.All;
return View();
}
//
// POST: /Address/Create
[HttpPost]
public ActionResult Create(Address address)
{
if (ModelState.IsValid) {
addressRepository.InsertOrUpdate(address);
addressRepository.Save();
return RedirectToAction("Index");
} else {
ViewBag.PossibleCountries = countryRepository.All;
return View();
}
}
//
// GET: /Address/Edit/5
public ActionResult Edit(int id)
{
ViewBag.PossibleCountries = countryRepository.All;
return View(addressRepository.Find(id));
}
//
// POST: /Address/Edit/5
[HttpPost]
public ActionResult Edit(Address address)
{
if (ModelState.IsValid) {
addressRepository.InsertOrUpdate(address);
addressRepository.Save();
return RedirectToAction("Index");
} else {
ViewBag.PossibleCountries = countryRepository.All;
return View();
}
}
//
// GET: /Address/Delete/5
public ActionResult Delete(int id)
{
return View(addressRepository.Find(id));
}
//
// POST: /Address/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
addressRepository.Delete(id);
addressRepository.Save();
return RedirectToAction("Index");
}
}
Country Controller
public class CountryController : Controller
{
private readonly ICountryRepository countryRepository;
// If you are using Dependency Injection, you can delete the following constructor
public CountryController() : this(new CountryRepository())
{
}
public CountryController(ICountryRepository countryRepository)
{
this.countryRepository = countryRepository;
}
//
// GET: /Country/
public ViewResult Index()
{
return View(countryRepository.All);
}
//
// GET: /Country/Details/5
public ViewResult Details(int id)
{
return View(countryRepository.Find(id));
}
//
// GET: /Country/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Country/Create
[HttpPost]
public ActionResult Create(Country country)
{
if (ModelState.IsValid) {
countryRepository.InsertOrUpdate(country);
countryRepository.Save();
return RedirectToAction("Index");
} else {
return View();
}
}
//
// GET: /Country/Edit/5
public ActionResult Edit(int id)
{
return View(countryRepository.Find(id));
}
//
// POST: /Country/Edit/5
[HttpPost]
public ActionResult Edit(Country country)
{
if (ModelState.IsValid) {
countryRepository.InsertOrUpdate(country);
countryRepository.Save();
return RedirectToAction("Index");
} else {
return View();
}
}
//
// GET: /Country/Delete/5
public ActionResult Delete(int id)
{
return View(countryRepository.Find(id));
}
//
// POST: /Country/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
countryRepository.Delete(id);
countryRepository.Save();
return RedirectToAction("Index");
}
}
Address Repository
public class AddressRepository : IAddressRepository
{
AddressTestContext context = new AddressTestContext();
public IQueryable<Address> All
{
get { return context.Addresses; }
}
public IQueryable<Address> AllIncluding(params Expression<Func<Address, object>>[] includeProperties)
{
IQueryable<Address> query = context.Addresses;
foreach (var includeProperty in includeProperties) {
query = query.Include(includeProperty);
}
return query;
}
public Address Find(int id)
{
return context.Addresses.Find(id);
}
public void InsertOrUpdate(Address address)
{
if (address.ID == default(int)) {
// New entity
context.Addresses.Add(address);
} else {
// Existing entity
address.CountryID = address.Country.ID;
context.Entry(address).State = EntityState.Modified;
}
}
public void Delete(int id)
{
var address = context.Addresses.Find(id);
context.Addresses.Remove(address);
}
public void Save()
{
context.SaveChanges();
}
}
public interface IAddressRepository
{
IQueryable<Address> All { get; }
IQueryable<Address> AllIncluding(params Expression<Func<Address, object>>[] includeProperties);
Address Find(int id);
void InsertOrUpdate(Address address);
void Delete(int id);
void Save();
}
Address CreateOrEdit.ascx View
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AddressTest.Models.Address>" %>
<div class="editor-label">
<%: Html.LabelFor(model => model.Street1) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Street1) %>
<%: Html.ValidationMessageFor(model => model.Street1) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Street2) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Street2) %>
<%: Html.ValidationMessageFor(model => model.Street2) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.City) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.City) %>
<%: Html.ValidationMessageFor(model => model.City) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.State) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.State) %>
<%: Html.ValidationMessageFor(model => model.State) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.PostalCode) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.PostalCode) %>
<%: Html.ValidationMessageFor(model => model.PostalCode) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Country) %>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Country.ID, ((IEnumerable<AddressTest.Models.Country>)ViewBag.PossibleCountries).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.Name),
Value = option.ID.ToString(),
Selected = (Model != null) && (option.ID == Model.CountryID)
}), "Choose...") %>
<%: Html.ValidationMessageFor(model => model.Country.ID) %>
</div>

Create the drop down list for the scalar property CountryID instead of Country.ID
<div class="editor-field">
<%: Html.DropDownListFor(model => model.CountryID, new SelectList((IEnumerable<AddressTest.Models.Country>)ViewBag.PossibleCountries, "ID", "Name"), "Choose...") %>
<%: Html.ValidationMessageFor(model => model.CountryID) %>
</div>
I would modify the Address POCO to make CountryID nullable and apply Required attribute
public class Address
{
public int ID { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
[ForeignKey("Country")]
[Required]
public int? CountryID { get; set; }
public Country Country { get; set; }
}

Related

Can't access to foreign key properties using Entity Framework in Razor Pages project

I'm trying to display foreign key properties values using class that should have access to it:
#foreach (var item in Model.UserIssues)
{
<div class="card scroll" style="width:22rem;">
<div class="card-header p-4">
<div class="d-flex justify-content-between">
<div>
<p class="card-label mb-0"></p>
<h5>#Html.DisplayFor(i => item.Case.CaseNumber)</h5>
</div>
<div>
<a class="btn button-idle-add" data-bs-toggle="tooltip" data-bs-title="Dodaj Pracownię" asp-route-id="#item.Id" asp-page="/Cases/AddLaboratory"><i class="fa-solid fa-plus"></i></a>
</div>
</div>
<div class="d-flex justify-content-between mt-3">
<div>
<p class="card-input">#Html.DisplayFor(e => item.Case.Principal)</p>
</div>
<div>
<p class="card-input">#Html.DisplayFor(e => item.Case.Date)</p>
</div>
</div>
</div>
<div class="card-body">
<div class="m-1 p-3 card-lab">
<div class="d-flex justify-content-between align-items-center">
<p>#Html.DisplayFor(e => item.IssueNumber)</p>
<p class="pe-3 ps-3" style="border-radius:15px; background-color: palegreen;"></p>
</div>
<p>#Html.DisplayFor(e => item.Specialist.Laboratory)</p>
<p>#Html.DisplayFor(e => item.Specialist.FullName)</p>
</div>
</div>
</div>
}
public class IndexModel : PageModel
{
private readonly IRepository<Issue> issueRepository;
private readonly IRepository<Specialist> specialistRepository;
public IndexModel(IRepository<Issue> issueRepository, IRepository<Specialist> specialistRepository)
{
this.issueRepository = issueRepository;
this.specialistRepository = specialistRepository;
}
public List<Issue> AllIssues { get; set; }
public async Task<IActionResult> OnGetAsync()
{
var loggedUser = specialistRepository.GetAll().FirstOrDefault(u => u.Login == User.Identity.Name);
UserIssues = issueRepository.GetAll().Where(i => i.Specialist.Id == loggedUser.Id).ToList();
return Page();
}
}
So for Specialist it works just fine:
#Html.DisplayFor(e => item.Specialist.FullName)
But for the Case it doesn't work, nothing is displayed:
#Html.DisplayFor(i => item.Case.CaseNumber)
Here are my models for Entity Framework setup:
public class Case
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "Uzupełnij pole")]
public string CaseNumber { get; set; }
[Required(ErrorMessage = "Uzupełnij pole")]
public string Principal { get; set; }
[Required(ErrorMessage = "Uzupełnij pole")]
public string Description { get; set; }
[Required(ErrorMessage = "Uzupełnij pole")]
public string Date { get; set; }
public ICollection<Issue> Issues { get; set; }
}
public class Issue
{
[Key]
public int Id { get; set; }
public string Comment { get; set; }
[Required(ErrorMessage = "Uzupełnij pole")]
public string IssueNumber { get; set; }
public Case Case { get; set; }
public Specialist Specialist { get; set; }
}
public class Specialist : IdentityUser
{
[Required]
public string Login { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Laboratory { get; set; }
public string FullName
{
get
{
return FirstName + " " + LastName;
}
}
public ICollection<Issue> Issues { get; set; }
}
Is my Entity Framework setup wrong? How can I display property values for the Case entity?
Using Entity Framework in case you want to get a specialist with id e775704b-5298-4173-82c8-c15d884e0695 and include the issues for this specialist you can use the include method in order to get the associated data.
Specialist? specialist = context.Specialists.Where(m => m.Id == "e775704b-5298-4173-82c8-c15d884e0695").Include(m => m.Issues).FirstOrDefault();
if (specialist != null)
{
foreach (var issue in specialist.Issues)
{
string issueNumber = issue.IssueNumber;
}
}
You can do the same thing for the entire list like this.
List<Specialist> specialists = context.Specialists.Include(m => m.Issues).ToList();
foreach (var specialist in specialists)
{
foreach (var issue in specialist.Issues)
{
string issueNumber = issue.IssueNumber;
}
}

Unable to update DbEnitity.! EnityValidation occurs! Customer parameter returns null when trying to edit or save it

I am using codefirst approach and entity framework to update my Customer by changing the name but EnityValidation Error occurs.As I try to debug it using trycatch block it shows the name field is required.
Error message while debugging
I used data annotation while using entity framework to my model class.
public class Customer
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Display(Name ="Date Of Birth")]
[DisplayFormat(ApplyFormatInEditMode =true,DataFormatString ="{0:dd/MM/yyyy}")]
public DateTime? Birthdate { get; set; }
public bool IsSubscribedToNewsletter { get; set; }
public MembershipType MembershipType { get; set; }
[Display(Name ="MembershipType")]
public byte MembershipTypeId { get; set; }
}
[Action-Save in CustomersController]
[HttpPost]
public ActionResult Save(Customer customer)
{
if (customer.Id == 0)
_context.Customers.Add(customer);
else
{
var customerInDb = _context.Customers.Single(c => c.Id == customer.Id);
customerInDb.Name = customer.Name;
customerInDb.Birthdate = customer.Birthdate;
customerInDb.IsSubscribedToNewsletter = customer.IsSubscribedToNewsletter;
customerInDb.MembershipTypeId = customer.MembershipTypeId;
}
try
{
_context.SaveChanges();
}
catch (DbEntityValidationException e)
{
Console.WriteLine(e);
}
return RedirectToAction("Index", "Customers");
}
[Edit-Action in CustomerController]
public ActionResult Edit(int id)
{
var customer = _context.Customers.SingleOrDefault(c => c.Id == id);
if (customer == null)
{
return HttpNotFound();
}
var viewModel = new CustomerFormViewModel
{
Customers = customer,
MembershipTypes = _context.MembershipType.ToList()
};
return View("CustomerForm", viewModel);
}
[New-Action CustomerController]
public ActionResult New()
{
var membershipType = _context.MembershipType.ToList();
var viewModel = new CustomerFormViewModel
{
MembershipTypes = membershipType
};
return View("CustomerForm", viewModel);
}
[CustomerFormViewModel -CustomerController]
public class CustomerFormViewModel
{
public IEnumerable<MembershipType> MembershipTypes { get; set; }
public Customer Customers { get; set; }
}
View-CustomerForm
#using (Html.BeginForm("Save","Customers"))
{
<div class="form-group">
#Html.LabelFor(c => c.Customers.Name)
#Html.TextBoxFor(c => c.Customers.Name,new{ #class="form-control"})
</div>
<div class="form-group">
#Html.LabelFor(c => c.Customers.Birthdate)
#Html.TextBoxFor(c => c.Customers.Birthdate,"{0:d MMM yyyy}" ,new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.Customers.MembershipTypeId)
#Html.DropDownListFor(c => c.Customers.MembershipTypeId,new SelectList(Model.MembershipTypes,"Id","Name"),"Select MembershipType",new { #class = "form-control" })
</div>
<div class="form-check">
<label>
#Html.CheckBoxFor(c => c.Customers.IsSubscribedToNewsletter) Subscribed To NewsLetter?
</label>
</div>
#Html.HiddenFor(c => c.Customers.Id)
<button type="submit" class="btn btn-primary">Save</button>
But this code works for another parameter "Movies".The movie object get passed.
[movies-model]
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public Genre Genre { get; set; }
public byte GenreId { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/mm/yyyy}")]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/mm/yyyy}")]
public DateTime DateAdded { get; set; }
public byte NumberInStock { get; set; }
}
[Edit-Action MovieController]
public ActionResult Edit(int id)
{
var movie = _context.Movies.SingleOrDefault(m => m.Id == id);
if (movie == null)
{
return HttpNotFound();
}
var viewModel = new MovieFormViewModel
{
Movie = movie,
Genres = _context.Genre.ToList()
};
return View("MovieForm",viewModel);
}
[New-Action MovieController]
public ActionResult New()
{
var genre = _context.Genre.ToList();
var viewModel = new MovieFormViewModel()
{
Genres = genre
};
return View("MovieForm", viewModel);
}
[Save-Action MovieController]
[HttpPost]
public ActionResult Save(Movie movie)
{
if(movie.Id==0)
{
movie.DateAdded = DateTime.Now;
_context.Movies.Add(movie);
}
else
{
var movieInDb = _context.Movies.SingleOrDefault(m => m.Id == movie.Id);
movieInDb.Name = movie.Name;
movieInDb.NumberInStock = movie.NumberInStock;
movieInDb.GenreId = movie.GenreId;
movieInDb.ReleaseDate = movie.ReleaseDate;
}
_context.SaveChanges();
return RedirectToAction("Index","Movies");
}
[MovieFormviewModel]
public class MovieFormViewModel
{
public Movie Movie { get; set; }
public IEnumerable<Genre> Genres { get; set; }
public string Title
{
get
{
if(Movie != null && Movie.Id !=0)
{
return "Edit Movie";
}
else
{
return "New Movie";
}
}
}
}
[movieForm-View]
#model Vidly.ViewModels.MovieFormViewModel
#{
ViewBag.Title = Model.Title;
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>New Movie</h2>
#using (Html.BeginForm("Save", "Movies"))
{
<div class="form-group">
#Html.LabelFor(m => m.Movie.Name)
#Html.TextBoxFor(m => m.Movie.Name,new { #class="form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Movie.ReleaseDate)
#Html.TextBoxFor(m => m.Movie.ReleaseDate, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Movie.GenreId)
#Html.DropDownListFor(m => m.Movie.GenreId,new SelectList(Model.Genres,"Id","Name"),"Select Genre", new { #class = "form-control"})
</div>
<div class="form-group">
#Html.LabelFor(m => m.Movie.NumberInStock)
#Html.TextBoxFor(m => m.Movie.NumberInStock, new { #class = "form-control" })
</div>
#Html.HiddenFor(m => m.Movie.Id)
<button type="submit" class="btn btn-primary">Save</button>
}
**How can i remove this error?Why is the object not getting passed for customers but for movies!!Both are basically same! **

MVC4 Entity Framework 5 Many-To-Many Save Entity to Database

Hi I've been stuck to long on this problem. I've looked at a lot of examples but i cant find what im looking for. Any help is appreciated.
I use the Code-First approach.
I've enabled migration and the database is fine [Student] - [StudentCourse] - [Course].
Scenario: I have two entites -> Student
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Course> Courses { get; set; }
}
And Course
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual List<Student> Students { get; set; }
}
Nothing fancy about that... Ive created a ViewModel ->
public class StudentCourseViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; }
}
View:
#model Project.Web.Models.StudentCourseViewModel #{
ViewBag.Title = "Edit"; }
Edit
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Student</legend>
#Html.HiddenFor(model => model.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Courses)
</div>
<div class="editor-field">
#for (int i = 0; i < Model.Students.Count(); i++)
{
<div style="border: dotted 1px; padding: 5px; margin: 10px;">
#Html.HiddenFor(s => s.Students[i].Id)
#Html.LabelFor(s => s.Students[i].Name[i + 1])
#Html.EditorFor(s => s.Students[i].Name)
</div>
}
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset> }
Controller Action:
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
var course = db.Courses.Find(model.CourseId);
course.Name = model.CourseName;
course.Description = model.CourseDescription;
course.Students = model.Students;
if (ModelState.IsValid)
{
db.Entry(course).State = System.Data.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
(Maby this is were i go wrong...)
Anyway, I want to create a new Student with optional many courses (textboxes -> courseName)
How should i do this?
The main issue is that i always get null values (student is fine, List of courses = NULL) back from my view [httpPost]Create -action.
I'm in need of guidance how to make this approach possible.
Thx J!
Your entities are not setup correctly for a many-to-many relationship. You need another entity to handle the many-to-many mapping. It would look something like this.
public class StudentsToCourses
{
public int StudentId {get; set;}
public int CourseId {get; set;}
public virtual Student Student {get; set;}
public virtual Course Course {get; set;}
}
Then your student model should be changed to this.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<StudentsToCourses> Courses { get; set; }
}
And your coursed model changed to this.
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual List<StudentsToCourses> Students { get; set; }
}
You also need to setup the foreign key relationship using the Fluent API. It would look something like this.
public class StudentsToCoursesConfiguration : EntityTypeConfiguration<StudentsToCourses>
{
internal StudentsToCoursesConfiguration ()
{
this.HasKey(p => new {p.StudentId, p.CourseId});
this.HasRequired(p => p.Student)
.WithMany(p => p.Courses)
.HasForeignKey(p => p.StudentId);
this.HasRequired(p => p.Course)
.WithMany(r => r.Students)
.HasForeignKey(p => p.CourseId);
}
}

MVC3 drop down list confusion

I'm using MVC3 with EF 4.1 and trying to edit a model which has a drop down list which is the reference to a parent object. Here are the models:
public class Section
{
public Guid SectionId { get; set; }
public string Title { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
public class Article
{
public Guid ArticleId { get; set; }
public DateTime? DatePosted { get; set; }
public string Title { get; set; }
public string ArticleBody { get; set; }
public Section Section { get; set; }
}
Here's the controller action to render the GET part of the edit:
public ActionResult Edit(Guid id)
{
Article article = db.Articles.Find(id);
var sections = db.Sections.ToList();
var secIndex = sections.IndexOf(article.Section);
ViewBag.SectionId = new SelectList(sections, "SectionId", "Title", secIndex);
return View(article);
}
And the View
#model CollstreamWebsite.Models.Article
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Article</legend>
#Html.HiddenFor(model => model.ArticleId)
<div class="editor-label">
#Html.LabelFor(model => model.DatePosted)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DatePosted)
#Html.ValidationMessageFor(model => model.DatePosted)
</div>
...
<div class="editor-label">
#Html.LabelFor(model => model.Section)
</div>
<div class="editor-field">
#Html.DropDownList("SectionId")
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
And finally the POST action for the edit
[HttpPost]
public ActionResult Edit(Article article)
{
if (ModelState.IsValid)
{
db.Entry(article).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
The problem I have is that when the HttpPost Edit comes back, article.Section is null. How do I force the View to bind the Section to the article being edited.
Any help appreciated.
Don't push your Model straight to your View. Use ViewModel instead.
Something like this:
ViewModel
public class EditArticleViewModel
{
///All the properties for your Article
///The SelectListItems for your Sections
public List<SelectListItem> Sections{ get; set; }
public String SelectedSection{ get; set; }
}
Edit Get
[HttpGet]
public ActionResult Edit(Guid id)
{
EditArticleViewModel oEditArticleViewModel = new EditArticleViewModel();
//Fill in the SelectLists
List<SelectListItem> Sections= new List<SelectListItem>();
Sections.Add(new SelectListItem() { Text = "TheSelectedSection", Value = SectionId.ToString(), Selected = true});
foreach(Section otherSection in AllPossibleSections)
{
Sections.Add(new SelectListItem() { Text = otherSection.Title, Value = otherSection.Id, Selected = false});
}
oEditArticleViewModel.Sections = Sections;
return View(oEditArticleViewModel );
}
Your View
#Html.DropDownListFor(model => model.SelectedSection, Model.Sections)
//All other needed properties with their textboxes etc.
Edit Post
[HttpPost]
public ActionResult Register(EditArticleViewModel oPostedViewModel)
{
if (ModelState.IsValid)
{
//Get the Article and fill in the new properties etc.
//You can get the selectedSection from the SelectedSection Property, just cast it to a Guid.
RedirectToAction("Index", "Home");
}
//Something went wrong, redisplay the form for correction.
//Make sure to fill in the SelectListItems again.
return View(oPostedViewModel);
}
Hope it helps

Populating properties on my Model with values from a SelectList when I post

I'm building an Asp.net MVC 2 application.
I have an entity called Team that is mapped via public properties to two other entities called Gender and Grade.
public class Team
{
public virtual int Id { get; private set; }
public virtual string CoachesName { get; set; }
public virtual string PrimaryPhone { get; set; }
public virtual string SecondaryPhone { get; set; }
public virtual string EmailAddress { get; set; }
public virtual Grade Grade { get; set; }
public virtual Gender Gender { get; set; }
}
I have a ViewModel that looks like this.
public class TeamFormViewModel
{
public TeamFormViewModel()
{
Team = new Team();
Grade = new SelectList((new Repository<Grade>()).GetList(),"ID", "Name",Team.Grade);
Gender = new SelectList((new Repository<Gender>()).GetList(), "ID", "Name", Team.Gender);
}
public Team Team { get; set; }
public virtual SelectList Grade { get; set; }
public virtual SelectList Gender { get; set; }
}
My form renders as I would expect. When I debug the Create method I see that the Gender and Grade properties are NULL on my Team object.
[HttpPost, Authorize]
public ActionResult Create(Team team)
{
try
{
if (ModelState.IsValid)
{
(new Repository<Team>()).Save(team);
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
What am I doing wrong?
Thanks,
Eric
I recommend that you post and bind back to a view model class rather than your entity class. Create an extension method for your view model class that will return your entity class. Here's some working code:
public class Team
{
public virtual int Id { get; set; }
public virtual string CoachesName { get; set; }
public virtual string PrimaryPhone { get; set; }
public virtual string SecondaryPhone { get; set; }
public virtual string EmailAddress { get; set; }
public virtual Grade Grade { get; set; }
public virtual Gender Gender { get; set; }
}
public class Grade
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Gender
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class TeamFormViewModel
{
public TeamFormViewModel()
{
var gradeList = (new Repository<Grade>()).GetList();
var genderList = (new Repository<Gender>()).GetList();
GradeList = new SelectList(gradeList, "Id", "Name");
GenderList = new SelectList(genderList, "Id", "Name");
}
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[DisplayName("Coach Name")]
[Required]
public string CoachesName { get; set; }
[DisplayName("Primary Phone")]
[DataType(DataType.PhoneNumber)]
[Required]
public string PrimaryPhone { get; set; }
[DisplayName("Secondary Phone")]
[DataType(DataType.PhoneNumber)]
public string SecondaryPhone { get; set; }
[DisplayName("Email Address")]
[DataType(DataType.EmailAddress)]
[Required]
public string EmailAddress { get; set; }
[DisplayName("Grade")]
[Range(1, 5)]
public int SelectedGradeId { get; set; }
[DisplayName("Gender")]
[Range(1, 5)]
public int SelectedGenderId { get; set; }
private int selectedGradeId = 0;
private int selectedGenderId = 0;
public SelectList GradeList { get; set; }
public SelectList GenderList { get; set; }
}
public static class TeamExtensions
{
public static Team ToTeam(this TeamFormViewModel viewModel)
{
return new Team
{
Id = viewModel.Id,
CoachesName = viewModel.CoachesName,
PrimaryPhone = viewModel.PrimaryPhone,
SecondaryPhone = viewModel.SecondaryPhone,
EmailAddress = viewModel.EmailAddress,
Grade = (new Repository<Grade>())
.GetList()
.Where(x => x.Id == viewModel.SelectedGradeId)
.Single(),
Gender = (new Repository<Gender>())
.GetList()
.Where(x => x.Id == viewModel.SelectedGradeId)
.Single()
};
}
public static TeamFormViewModel ToTeamFormViewModel(this Team team)
{
return new TeamFormViewModel
{
Id = team.Id,
CoachesName = team.CoachesName,
PrimaryPhone = team.PrimaryPhone,
SecondaryPhone = team.SecondaryPhone,
EmailAddress = team.EmailAddress,
SelectedGradeId = team.Grade.Id,
SelectedGenderId = team.Gender.Id
};
}
}
public class TeamController : Controller
{
public ActionResult Create()
{
var viewModel = new TeamFormViewModel();
return View(viewModel);
}
[HttpPost]
public ActionResult Create(TeamFormViewModel viewModel)
{
if (ModelState.IsValid)
{
(new Repository<Team>())
.Save(viewModel.ToTeam());
}
return View(viewModel);
}
}
And finally, the view:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Stack1.Models.TeamFormViewModel>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Create</title>
<script type="text/javascript" src="/Scripts/jquery-1.4.1.js"></script>
<script type="text/javascript" src="/Scripts/MicrosoftAjax.js"></script>
<script type="text/javascript" src="/Scripts/MicrosoftMvcValidation.js"></script>
</head>
<body>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>
<%= Html.ValidationSummary() %>
<fieldset>
<legend>Fields</legend>
<%= Html.LabelFor(x => x.CoachesName) %>
<p>
<%= Html.TextBoxFor(x => x.CoachesName) %>
<%= Html.ValidationMessageFor(x => x.CoachesName) %>
</p>
<%= Html.LabelFor(x => x.PrimaryPhone)%>
<p>
<%= Html.EditorFor(x => x.PrimaryPhone) %>
<%= Html.ValidationMessageFor(x => x.PrimaryPhone)%>
</p>
<%= Html.LabelFor(x => x.SecondaryPhone)%>
<p>
<%= Html.EditorFor(x => x.SecondaryPhone) %>
<%= Html.ValidationMessageFor(x => x.SecondaryPhone)%>
</p>
<%= Html.LabelFor(x => x.EmailAddress)%>
<p>
<%= Html.EditorFor(x => x.EmailAddress) %>
<%= Html.ValidationMessageFor(x => x.EmailAddress)%>
</p>
<%= Html.LabelFor(x => x.SelectedGradeId)%>
<p>
<%= Html.DropDownListFor(x => x.SelectedGradeId, Model.GradeList) %>
<%= Html.ValidationMessageFor(x => x.SelectedGradeId)%>
</p>
<%= Html.LabelFor(x => x.SelectedGenderId)%>
<p>
<%= Html.DropDownListFor(x => x.SelectedGenderId, Model.GenderList) %>
<%= Html.ValidationMessageFor(x => x.SelectedGenderId)%>
</p>
<p>
<%= Html.HiddenFor(x => x.Id) %>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
</body>
</html>