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

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! **

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>

How to save an image to Database using MVC 4

So I have a project which is a Shopping Cart, I have to save images to the database instead of uploading them to the server, here is my model
namespace ShoppingCart.Models
{
[Bind(Exclude = "ItemID")]
public class Item
{
[ScaffoldColumn(false)]
public int ItemID { get; set; }
[DisplayName("Category")]
public int CategoryID { get; set; }
[DisplayName("Brand")]
public int BrandID { get; set; }
[Required(ErrorMessage = "A Name is required")]
[StringLength(160)]
public string Title { get; set; }
public string Description { get; set; }
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00,
ErrorMessage = "Price must be between 0.01 and 500.00")]
public decimal Price { get; set; }
[DisplayName("Album Art URL")]
[StringLength(1024)]
public string ItemArtUrl { get; set; }
public byte[] Picture { get; set; }
public virtual Category Category { get; set; }
public virtual Brand Brand { get; set; }
public virtual List<OrderDetail> OrderDetails { get; set; }
}
}
So Im unsure how to go about the controller to insert images or the view to display them, I have search for information about this but I cant really find anything, Im using entity framework code first.
There are two easy ways to do images -- one is to simply return the image itself in the controller:
[HttpGet]
[AllowAnonymous]
public ActionResult ViewImage(int id)
{
var item = _shoppingCartRepository.GetItem(id);
byte[] buffer = item.Picture;
return File(buffer, "image/jpg", string.Format("{0}.jpg", id));
}
And the view would just reference it:
<img src="Home/ViewImage/10" />
Additionally, you can include it in the ViewModel:
viewModel.ImageToShow = Convert.ToBase64String(item.Picture);
and in the view:
#Html.Raw("<img src=\"data:image/jpeg;base64," + viewModel.ImageToShow + "\" />");
For the data-store, you would simply use a byte array (varbinary(max)) or blob or any compatible type.
Uploading images
Here, an object called HeaderImage is an EntityFramework EntityObject. The controller would look something like:
[HttpPost]
public ActionResult UploadImages(HttpPostedFileBase[] uploadImages)
{
if (uploadImages.Count() <= 1)
{
return RedirectToAction("BrowseImages");
}
foreach (var image in uploadImages)
{
if (image.ContentLength > 0)
{
byte[] imageData = null;
using (var binaryReader = new BinaryReader(image.InputStream))
{
imageData = binaryReader.ReadBytes(image.ContentLength);
}
var headerImage = new HeaderImage
{
ImageData = imageData,
ImageName = image.FileName,
IsActive = true
};
imageRepository.AddHeaderImage(headerImage);
}
}
return RedirectToAction("BrowseImages");
}
The View would look something like:
#using (Html.BeginForm("UploadImages", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<span class="span4">
<input type="file" name="uploadImages" multiple="multiple" class="input-files"/>
</span>
<span class="span2">
<input type="submit" name="button" value="Upload" class="btn btn-upload" />
</span>
</div>
}

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

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