Populating properties on my Model with values from a SelectList when I post - asp.net-mvc-2

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>

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

selectList razor tag helpers asp.netCore

I want to make a drop down list of "Trailers" and "Customers" available in my "Order" form. I am able to use the Html tag helper to pass Trailer data from database to the view in the "Order" form but i am not able to do the same for Customers using the razor select tag helper. Why isn't the razor select tag helper not passing values from the database to the view? Below are snippets of my code. I am confused as to why it's not working
Trailer Class
public class Trailer
{
public string SerialNumber { get; set; }
public string TrailerNumber { get; set; }
public string TrailerStatus { get; set; }
public int TrailerID { get; set; }
public virtual Order OrderforTrailer { get; set; }
public Trailer()
{
TrailerStatus = "Available";
}
}
Customer class
public class Customer
{
public string CustomerName { get; set; }
public string StreetNumber { get; set; }
public string StreetName { get; set; }
public string ZipCode { get; set; }
public string State { get; set; }
public int CustomerID { get; set; }
public IList<Order> CustomerOrders { get; set; }
}
Order Class
public class Order
{
public string OrderNumber { get; set; }
public string OrderStatus { get; set; }
public int OrderID { get; set; }
public int TrailerForLoadID { get; set; }
public virtual Trailer TrailerForLoad { get; set; }
public int CustomerOrdersID { get; set;}
public virtual Customer CustomerOrders { get; set; }
public Order()
{
OrderStatus = "Available";
}
}
AddOrderViewModel
public string OrderNumber { get; set; }
public int TrailerID { get; set; }
public List<SelectListItem> TrailersForLoad { get; set; }
public int CustomerID { get; set; }
public List<SelectListItem> CustomersOrder { get; set; }
public AddOrderViewModel()
{
}
public AddOrderViewModel(IEnumerable<Trailer> trailersForLoad, IEnumerable<Customer> customersOrder)
{
TrailersForLoad = new List<SelectListItem>();
foreach (var trailer in trailersForLoad)
{
TrailersForLoad.Add(new SelectListItem
{
Value = (trailer.TrailerID).ToString(),
Text = trailer.TrailerNumber
});
};
CustomersOrder = new List<SelectListItem>();
foreach (var customer in customersOrder)
{
CustomersOrder.Add(new SelectListItem
{
Value = (customer.CustomerID).ToString(),
Text = customer.CustomerName
});
};
}
}
Order controller
public IActionResult Add()
{
IList<Trailer> trailerForLoad = context.Trailers.Where
(c => c.TrailerStatus == "Available").ToList();
IList<Customer> customerOrder = context.Customers.ToList();
AddOrderViewModel addOrderViewModel =
new AddOrderViewModel(trailerForLoad, customerOrder);
return View(addOrderViewModel);
}
[HttpPost]
public IActionResult Add(AddOrderViewModel addOrderViewModel)
{
if (ModelState.IsValid)
{
Order newOrder = new Order()
{
OrderNumber = addOrderViewModel.OrderNumber,
TrailerForLoad = context.Trailers.
Where(x => x.TrailerID == addOrderViewModel
.TrailerID).Single(),
CustomerOrders = context.Customers
.Single(x => x.CustomerID==addOrderViewModel.CustomerID)
};
context.Orders.Add(newOrder);
trailerSelected = context.Trailers.Where(x =>
x.TrailerID == addOrderViewModel.TrailerID).Single();
trailerSelected.TrailerStatus = "Unavailable";
context.SaveChanges();
return Redirect("/Order");
}
return View(addOrderViewModel);
}
The form in the view should display a list of customers
<form asp-controller="Order" asp-action="Add" method="post">
<fieldset>
<div class="form-group">
<label asp-for="OrderNumber">Order number </label>
<input class="form-control" asp-for="OrderNumber" />
<span asp-validation-for="OrderNumber"></span>
</div>
<div class="form-group">
<label asp-for="TrailersForLoad">Trailer</label>
#Html.DropDownListFor(x => x.TrailerID, Model.TrailersForLoad)
<span asp-validation-for="TrailersForLoad"></span>
</div>
<div class="form-group">
<label asp-for="CustomerID">Customers Name</label>
<select asp-for="CustomerID"
asp-items="Model.CustomersOrder"></select>
<span asp-validation-for="CustomerID"></span>
</div>
<div>
<input type="submit" value="Submit" name="submitButton" />
</div>
</fieldset>
You are using the SELECT tag helper incorrectly. In your current code, you are using a self closing tag approach! Instead you should use an explicit </SELECT> closing tag
This should work
<select asp-for="CustomerID" asp-items="Model.CustomersOrder"></select>

DbUpdateConcurrencyException not raised Database First

I am currently following this tutorial for Concurrency Handling.
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
However, the DbUpdateConcurrencyException is not raised in my case. I'm using Database first approach in EF 5.0
I have Carrier object with 0..1 relationship with Address & Contact objects.
I have created the a RowVersion field in the Carrier table .
My code is as follows:
public Carrier UpdateCarrier(Carrier carrier)
{
try
{
var entry = ariesConfigContext.Entry<Carrier>(carrier);
if(entry.State == System.Data.EntityState.Detached)
{
var attachedEntity = ariesConfigContext.Carriers.Include(con => con.Contact).Include(a => a.Address).Single(c => c.CarrierID == carrier.CarrierID);
if(attachedEntity != null)
{
var attachedEntry = ariesConfigContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(carrier);
attachedEntity.Contact = carrier.Contact;
attachedEntity.Address = carrier.Address;
}
else
{
entry.State = System.Data.EntityState.Modified;
}
}
ariesConfigContext.SaveChanges();
}
catch(DbUpdateConcurrencyException ex)
{
//do something
}
return carrier;
}
My Model is as follows:
namespace Aries.Domain.Models.AriesConfigDB
{
using System;
using System.Collections.Generic;
public partial class Carrier
{
public Carrier()
{
this.UserProfiles = new HashSet<UserProfile>();
}
public int CarrierID { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Memo { get; set; }
public string DBServerName { get; set; }
public string DBName { get; set; }
public string DBUser { get; set; }
public string DBPassword { get; set; }
public Nullable<int> AddressID { get; set; }
public Nullable<int> ContactID { get; set; }
public bool IsDeleted { get; set; }
public byte[] RowVersion { get; set; }
public virtual Address Address { get; set; }
public virtual Contact Contact { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
}
My View is:
#model Aries.Domain.Models.AriesConfigDB.Carrier
<div>
<div class="message-error">
#if (TempData["ErrorMessage"] != null)
{
<p>#TempData["ErrorMessage"]</p>
}
</div>
#Html.HiddenFor(model => model.CarrierID)
#Html.HiddenFor(model => model.RowVersion)
<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.Abbreviation)
</div>
....
....
I'm unable to get the Exception to be raised. Any help is appreciated.
UPDATE:
I already have a Metadata class for Carrier as below and I've added the [Timestamp] attribute there.
public class CarrierMetadata
{
public int CarrierID { get; set; }
[Required]
[MaxLength(255, ErrorMessage = "Carrier Name must be 255 characters or less")]
[Display(Name = "Carrier Name")]
public string Name { get; set; }
....
....
[Required]
[ConcurrencyCheck]
[Timestamp]
public byte[] RowVersion { get; set; }
}
And my Carrier class has the following attribute:
[MetadataType(typeof(CarrierMetadata))]
public partial class Carrier
{
}
But it still doesn't work.

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

Combined Multiple Models into Single View - Create Problem

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