Why always in the database, the DateTime property is null? - asp.net-mvc

i 'm beginner in programming with MVC5.
I am working with MVC5 and Entity framework 6.
I have a class and a DateTime property like this:
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",ApplyFormatInEditMode = true)]
[Column(TypeName = "datetime2")]
public DateTime? BirthDay { get; set; }
my controller:
public ActionResult Create([Bind(Include = "MelliCode,EnCode,grade,quota,password,FName,Lname,shenasname,FatehrName,sex,tel,mobile,ResAddress,WorkAddress")] Expert expert)
{
if (ModelState.IsValid)
{
db.Experts.Add(expert);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(expert);
}
and my view like this:
<div class="form-group">
#Html.LabelFor(model => model.BirthDay, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BirthDay, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BirthDay, "", new { #class = "text-danger" })
</div>
However, after the run of the page and enter personal information in the database is inserted to null for Birthday!!!why?

I found my problem
I had forgotten Birthday in [Bind] attribute
public ActionResult Create([Bind(Include = "BirthDay,MelliCode,EnCode,grade,quota,password,FName,Lname,shenasname,FatehrName,sex,tel,mobile,ResAddress,WorkAddress")] Expert expert)
{
if (ModelState.IsValid)
{
db.Experts.Add(expert);
db.SaveChanges();
return RedirectToAction("Index");
}

Related

Unable to edit the user information in mvc

Here is my problem , So i wanted to only allowing the user to change/edit their password and username only.
My original model for customer is this
public string IC { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username{ get; set; }
public string Password{ get; set; }
And this is my VM for the customer
public string Username{ get; set; }
public string Password{ get; set; }
And this is my controller for the edit function
public ActionResult Edit([Bind(Include = "Username,Password")] CustomersVM customersVM )
{
if (ModelState.IsValid)
{
db.Entry(customersVM ).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customersVM );
}
view.cshtml
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.IC)
<div class="form-group">
#Html.LabelFor(model => model.Username, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Username, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Username, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Password, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</div>
</div>
So this VM is to let the ModelState goes valid, which is will going right into the database but it turn out to turn this type of error
System.InvalidOperationException: 'The entity type CustomerVM is not part of the model for the current context.'
In order to edit/update a record, you need to identify that record first. I your case, your ViewModel is not what your database holds but the first model in your question. So you need to map that viewModel to the real model before saving or fetch the existing record then modify it then set it as modified before saving.
public ActionResult Edit([Bind(Include = "Username,Password")] CustomersVM customersVM )
{
if (ModelState.IsValid)
{
var existing = db.Customers.FirstOrDefault(x => x.Id == customersVM.Id);
if (existing != null)
{
existing.Username = customersVM.Username;
existing.Password = customerVM.Password;
db.Entry(existing ).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(customersVM );
}

how i can send multivalue to create action

i have a doctor i want add doctor subspecialty to the doctor from sub specialties table many to many relationship
i need to add subspecialties from multiselect list but my controller only add first selection , i want my create controller take all passed subspecialties and create it
my model
public partial class DoctorSubSpecialty
{
public int Id { get; set; }
public Nullable<int> DoctorId { get; set; }
public Nullable<int> SubSpecialtyId { get; set; }
public virtual DoctorProfile DoctorProfile { get; set; }
public virtual SubSpecialty SubSpecialty { get; set; }
}
}
create get action
public ActionResult Create()
{
ViewBag.DoctorId = new SelectList(db.DoctorProfiles, "Id", "FullName");
ViewBag.SubSpecialtyId = new MultiSelectList(db.SubSpecialties, "id", "Name");
return View();
}
create post action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Id,DoctorId,SubSpecialtyId")] DoctorSubSpecialty doctorSubSpecialty)
{
DoctorSubSpecialty doctorSub = db.DoctorSubSpecialties.Where(d => d.DoctorId == doctorSubSpecialty.DoctorId & d.SubSpecialtyId == doctorSubSpecialty.SubSpecialtyId).FirstOrDefault();
if (doctorSub == null) {
db.DoctorSubSpecialties.Add(doctorSubSpecialty);
await db.SaveChangesAsync();
}
my view
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DoctorSubSpecialty</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.DoctorId, "DoctorId", htmlAttributes: new { #class = "control-label col-md-2", #id = "DoctorID" })
<div class="col-md-10">
#Html.DropDownList("DoctorId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DoctorId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SubSpecialtyId, "SubSpecialtyId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SubSpecialtyId",(MultiSelectList)ViewBag.SubSpecialtyId, htmlAttributes: new { #multiple = "multiple", #class = "form-control" })
#Html.ValidationMessageFor(model => model.SubSpecialtyId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Create a ViewModel specific to your usecase that can actually transport more than one Id.
I.e. you will need an int[] to bind the selection to.
A ViewModel also helps you to get rid of all this ViewBag and [Bind] nonsense.
public class CreateDoctorSubSpecialtyViewModel {
// These are the selected values to be posted back
public int DoctorId { get; set; }
public int[] SubSpecialtyIds { get; set; }
// These are the possible values for the dropdowns
public IEnumerable<SelectListItem> DoctorProfiles { get; set; }
public IEnumerable<SelectListItem> SubSpecialties { get; set; }
}
GET action - initialize the ViewModel and pass it to the View:
[HttpGet]
public ActionResult Create() {
var doctorProfiles = db.DoctorProfiles.Select(d =>
new SelectListItem {
Text = d.FullName,
Value = d.Id
}
).ToArray();
var subSpecialties = db.SubSpecialties.Select(s =>
new SelectListItem {
Text = s.Name,
Value = s.id
}
).ToArray();
var viewModel = new CreateDoctorSubSpecialtyViewModel {
DoctorProfiles = doctorProfiles,
SubSpecialties = subSpecialties
};
return View("Create", viewModel);
}
View "Create.cshtml" (styling removed for clarity) - tell MVC which ViewModel we want to use with #model:
#model CreateDoctorSubSpecialtyViewModel
#using (Html.BeginForm("Create", "YourControllerName", FormMethod.Post)) {
#Html.DropDownListFor(m => m.DoctorId, Model.DoctorProfiles)
#Html.DropDownListFor(m => m.SubSpecialtyIds, Model.SubSpecialties, new { multiple = "multiple" })
<input type="submit" />
}
POST action - use Linq Contains to test against multiple submitted SubSpecialtyIds:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(CreateDoctorSubSpecialtyViewModel postData) {
DoctorSubSpecialty[] allSelectedSubSpecialities = db.DoctorSubSpecialties
.Where(d => d.DoctorId == postData.DoctorId
&& postData.SubSpecialtyIds.Contains(d.SubSpecialtyId))
.ToArray();
// ...
}
EDIT #Html.DropDownListFor requires an IEnumerable<SelectListItem> as second parameter.

ValidationMessage in MVC View not displaying

I have a custom date validation and I have done as explained in
this link. Below is my Model code:
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",ApplyFormatInEditMode=true)]
[DisplayName("Sch.Start Date:")]
[DataType(DataType.Date)]
[ValidProjectDate(ErrorMessage="Project Start Date cannot be greater than Project End Date.")]
public DateTime? ProjectScheduleStartDate { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
[DisplayName("Sch.End Date:")]
[DataType(DataType.Date)]
[ValidProjectDate(ErrorMessage = "Project End Date cannot be less than or Equal to Current Date.")]
public DateTime? ProjectScheduleEndDate { get; set; }
`
Below is my code in View:
<div class="form-group">
#Html.LabelFor(model => model.ProjectScheduleStartDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ProjectScheduleStartDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProjectScheduleStartDate, "*", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ProjectScheduleEndDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ProjectScheduleEndDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProjectScheduleEndDate, "*", new { #class = "text-danger" })
</div>
</div>
<hr/>
#Html.ValidationSummary(true, "Please correct below errors", new { #class = "text-danger" })
Below is my code in Controller:
if (ModelState.IsValid)
{
ProjectManager pm = new ProjectManager();
pm.AddProjects(prj);
ViewBag.Result = "Record Inserted Successfully.";
ModelState.Clear();
}
else
{
ModelState.AddModelError(string.Empty, "An Error has happened");
}
return View("AddNewProject");
Even though I tried to display the validation message as mentioned in the model class, I am getting only star images instead of the validation messages. However, the Error messsages specified inside the validation summary is getting displayed. But I want to display the messages in the model class. Any clue?
I removed the star symbol on the ValidationMessageFor in View. It started working.. May be helpful for someone.
Your attribute's ValidationResult does not have a key associated with a field, which prevents ValidationMessageFor from working.
I would suggest using implementing the IValidatable interface on your ViewModel instead of your custom data validation attribute, unless there are many places in your application where this type of validation is required.
You will notice that it provides the name of the property as the key to associate the error with the field:
public class TestViewModel : IValidatableObject
{
public DateTime? ProjectStartDate { get; set; }
public DateTime? ProjectEndDate { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ProjectStartDate > ProjectEndDate)
yield return new ValidationResult("The Project Start Date cannot be after the Project End Date.", new List<string>() { nameof(ProjectStartDate) });
if (ProjectEndDate < DateTime.Now)
yield return new ValidationResult("Project End Date cannot be less than or Equal to Current Date.", new List<string>() { nameof(ProjectEndDate) });
}
}

How to save dropdownlist selected value to the database int asp.net MVC 5

I am currently new to Asp.net MVC .In one of the view I add a dropdownlist and I bind this dropdownlist with my database like this
Controller CollegeController
[HttpGet]
public ActionResult Create()
{
IEnumerable<SelectListItem> items = db.College_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Name });
IEnumerable<SelectListItem> item = db.Stream_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Stream });
ViewBag.CollName=items;
ViewBag.StreamName = item;
return View();
}
[HttpPost]
public ActionResult Create(College college)
{
try
{
if(ModelState.IsValid)
{
db.Colleges.Add(college);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CollName = db.Colleges;
return View(college);
}
catch
{
return View();
}
}
This is my model
public class College
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name="College Name")]
public int CollegeName { get; set; }
[Required]
public int Stream { get; set; }
[Required]
[Column(TypeName="varchar")]
public string Name { get; set; }
....
public virtual College_Name College_Name { get; set; }
public virtual Stream_Name Stream_Name { get; set; }
}
This is My View
<div class="form-group">
#Html.LabelFor(model => model.CollegeName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CollName", (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CollegeName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Stream, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StreamName", (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Stream, "", new { #class = "text-danger" })
</div>
</div>
Now when I check my database after I save the CollegeName and Stream in the database is zero from the dropdownlist.
You have multiple problems with your code. Firstly you dropdownlists are binding to a properties named CollName and StreamName which do not even exist in your model.
Next you cannot name the property your binding to the same as the ViewBag property.
Your view code would need to be (and always use the strongly typed xxxFor() HtmHelper methods
#Html.DropDownListFor(m => m.CollegeName, (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.Stream, (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" }
and in your POST method, the values of college.CollegeName and college.Stream will contain the ID's of the selected options.
You also need to repopulate the ViewBag properties when you return the view in the POST method (as you did in the GET method) or an exception will be thrown (and note that your current use of ViewBag.CollName = db.Colleges; will also throw an exception)
I also strongly suggest you start learning to use view models (views for editing should not use data models - refer What is ViewModel in MVC?) - and use naming conventions that reflect what your properties are, for example CollegeNameList, or CollegeNames, not CollName

MVC how to retrieve the current date and time in a view

I have been looking for a while now and can't seem to find the answer. What I am trying to do is have the current date and the current Time in two fields on a create page. This page will be used for basic journey scheduling.
What I have so far is my model
public class Journey
{
public int JourneyId { get; set; }
public string Name { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}",ApplyFormatInEditMode = true)]
public DateTime Departure { get; set; }
[DataType(DataType.Time)]
[DisplayFormat(DataFormatString="{0:hh\\:mm}", ApplyFormatInEditMode = true)]
public TimeSpan DepartureTime { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime Arrival { get; set; }
public string Description { get; set; }
public int FareId { get; set; }
public int TrainId { get; set; }
public virtual FareType FareType { get; set; }
public virtual Train Train { get; set; }
}
Account Controller
public class JourneyController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
//
// GET: Journey
public ActionResult Index()
{
return View(db.Journey.ToList());
}
//
// GET: Journey/Create
public ActionResult Create()
{
ViewBag.TrainId = new SelectList(db.Train, "TrainId", "Name");
return View();
}
// POST: Journey/Create
[HttpPost]
public ActionResult Create(Journey model)
{
try
{
if (ModelState.IsValid)
{
db.Journey.Add(model);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TrainId = new SelectList(db.Train, "TrainId", "Name", model.TrainId);
return RedirectToAction("Index");
}
catch (DataException)
{
ModelState.AddModelError("", "Sorry something went wrong");
}
return View(model);
}
}
And finaly my view
<div class="form-horizontal">
<h4>Journey</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Departure, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Departure, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Departure, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DepartureTime, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DepartureTime., new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DepartureTime, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Arrival, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Arrival, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Arrival, "", new { #class = "text-danger" })
</div>
</div>
Any help would be great
Many thanks
Use custom getters and setters on your DateTime property to provide a default of now:
private DateTime? departure;
public DateTime Departure
{
get { return departure ?? DateTime.Today; }
set { departure = value; }
}
private DateTime? departureTime;
public DateTime DepartureTime
{
get { return departureTime ?? DateTime.Now; }
set { departureTime = value; }
}
private DateTime? arrival;
public DateTime Arrival
{
get { return arrival ?? DateTime.Today; }
set { arrival = value; }
}
Alternatively, you can just manually set the values in your action:
public ActionResult Create()
{
var journey = new Journey
{
Departure = DateTime.Today,
DepartureTime = DateTime.Now,
Arrival = DateTime.Today
};
ViewBag.TrainId = new SelectList(db.Train, "TrainId", "Name");
return View(journey);
}

Resources