Platform: Windows 7 Ultimate
IDE: Visual Studio 2010 Ultimate
Web Environment: ASP.NET MVC 2
Database: SQL Server 2008 R2 Express
Data Access: Entity Framework 4
Form Validation: DataAnnotations
Sample App: NerdDinner from Wrox Pro ASP.NET MVC 2
Book: Wrox Professional MVC 2
Problem with Chapter 1 - Section: "Integrating Validation and Business Rule Logic with Model Classes" (pages 33 to 35)
ERROR Synopsis: NerdDinner form validation ERROR with DataAnnotations and db nulls.
DataAnnotations in sample code does not work when the database fields are set to not allow nulls.
ERROR occurs with the code from the book and with the sample code downloaded from codeplex.
Help! I'm really frustrated by this!! I can't believe something so simple just doesn't work???
Steps to reproduce ERROR:
- Set Database fields to not allow NULLs (See Picture)
- Set NerdDinnerEntityModel Dinner class fields' Nullable property to false (See Picture)
- Add DataAnnotations for Dinner_Validation class (CODE A)
- Create Dinner repository class (CODE B)
- Add CREATE action to DinnerController (CODE C)
- This is blank form before posting (See Picture)
- This null ERROR occurs when posting a blank form which should be intercepted by the Dinner_Validation class DataAnnotations. Note ERROR message says that "This property cannot be set to a null value. WTH??? (See Picture)
- The next ERROR occurs during the edit process. Here is the Edit controller action (CODE D)
- This is the "Edit" form with intentionally wrong input to test Dinner Validation DataAnnotations (See Picture)
- The ERROR occurs again when posting the edit form with blank form fields. The post request should be intercepted by the Dinner_Validation class DataAnnotations. Same null entry error. WTH??? (See Picture)
See screen shots at:
http://www.intermedia4web.com/temp/nerdDinner/StackOverflowNerdDinnerQuestionshort.png
CODE A:
[MetadataType(typeof(Dinner_Validation))]
public partial class Dinner { }
[Bind(Include = "Title, EventDate, Description, Address, Country, ContactPhone, Latitude, Longitude")]
public class Dinner_Validation
{
[Required(ErrorMessage = "Title is required")]
[StringLength(50, ErrorMessage = "Title may not be longer than 50 characters")]
public string Title { get; set; }
[Required(ErrorMessage = "Description is required")]
[StringLength(265, ErrorMessage = "Description must be 256 characters or less")]
public string Description { get; set; }
[Required(ErrorMessage="Event date is required")]
public DateTime EventDate { get; set; }
[Required(ErrorMessage = "Address is required")]
public string Address { get; set; }
[Required(ErrorMessage = "Country is required")]
public string Country { get; set; }
[Required(ErrorMessage = "Contact phone is required")]
public string ContactPhone { get; set; }
[Required(ErrorMessage = "Latitude is required")]
public double Latitude { get; set; }
[Required(ErrorMessage = "Longitude is required")]
public double Longitude { get; set; }
}
CODE B:
public class DinnerRepository
{
private NerdDinnerEntities _NerdDinnerEntity = new NerdDinnerEntities();
// Query Method
public IQueryable<Dinner> FindAllDinners()
{
return _NerdDinnerEntity.Dinners;
}
// Query Method
public IQueryable<Dinner> FindUpcomingDinners()
{
return from dinner in _NerdDinnerEntity.Dinners
where dinner.EventDate > DateTime.Now
orderby dinner.EventDate
select dinner;
}
// Query Method
public Dinner GetDinner(int id)
{
return _NerdDinnerEntity.Dinners.FirstOrDefault(d => d.DinnerID == id);
}
// Insert Method
public void Add(Dinner dinner)
{
_NerdDinnerEntity.Dinners.AddObject(dinner);
}
// Delete Method
public void Delete(Dinner dinner)
{
foreach (var rsvp in dinner.RSVPs)
{
_NerdDinnerEntity.RSVPs.DeleteObject(rsvp);
}
_NerdDinnerEntity.Dinners.DeleteObject(dinner);
}
// Persistence Method
public void Save()
{
_NerdDinnerEntity.SaveChanges();
}
}
CODE C:
// **************************************
// GET: /Dinners/Create/
// **************************************
public ActionResult Create()
{
Dinner dinner = new Dinner() { EventDate = DateTime.Now.AddDays(7) };
return View(dinner);
}
// **************************************
// POST: /Dinners/Create/
// **************************************
[HttpPost]
public ActionResult Create(Dinner dinner) {
if (ModelState.IsValid)
{
dinner.HostedBy = "The Code Dude";
_dinnerRepository.Add(dinner);
_dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
else
{
return View(dinner);
}
}
CODE D:
// **************************************
// GET: /Dinners/Edit/{id}
// **************************************
public ActionResult Edit(int id)
{
Dinner dinner = _dinnerRepository.GetDinner(id);
return View(dinner);
}
// **************************************
// POST: /Dinners/Edit/{id}
// **************************************
[HttpPost]
public ActionResult Edit(int id, FormCollection formValues)
{
Dinner dinner = _dinnerRepository.GetDinner(id);
if (TryUpdateModel(dinner)){
_dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
return View(dinner);
}
I have sent Wrox and one of the authors a request for help but have not heard back from anyone. Readers of the book cannot even continue to finish the rest of chapter 1 because of these errors. Even if I download the latest build from Codeplex, it still has the same errors. Can someone please help me and tell me what needs to be fixed? Thanks - Ed.