Entity Framework DateTime format when editing entry - asp.net

I have a Timetable model which only has two attributes at the moment, an Id and Date. It's defined as so:
public class Timetable
{
public int Id { get; set; }
[Required, Column(TypeName = "Date"), DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime Date { get; set; }
}
I then scaffolded some basic CRUD functionality, and thanks to the DisplayFormat annotation it's allowing me to create timetables with dates in the dd/MM/yyyy format. However, when I edit an existing timetable, the application is populating the Date text box with 01/01/2015 00:00:00 (see screenshot).
Is there any way to make my application only use the date, rather than date and time?

In order to render the browsers datepicker (<input type="date" ..>) using EditorFor() you need the following attributes on the property (note the ISO format means the date will be displayed in accordance with the browser culture)
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode=true)]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
and in the view
#Html.EditorFor(m => m.Date)
Note the HTML5 date input is not supported in older browsers, and not at all in FireFox - see comparison here

Related

How to set DataAnnotations for Date in Database First EF 6 on MVC5

There is a method to set format in Code First Migration
i.e:
..
[DisplayFormat(ApplyFormatInEditMode=true, DataFormatString = "{0:d}")]
public Nullable<System.DateTime> DeliveredDate { get; set; }
..
However, I could achieve same logic in Database First Migration, since every change is the database is updating the models.
So, my question is: How to set DataAnnotations like (DisplayFormat, DataFormatString so on.) in Database first migration? Is is possible? If possible, how to implement it.
You can utilize the fact that the generated entity classes are partial and associate metadata though another class and MetadataTypeAttribute.
E.g., in some code file not affected by the code generation, you would write something like this:
[MetadataType(typeof(YourEntityMetadata))]
partial class YourEntity { }
class YourEntityMetadata
{
[DisplayFormat(ApplyFormatInEditMode=true, DataFormatString = "{0:d}")]
public Nullable<System.DateTime> DeliveredDate { get; set; }
}
The "metadata" class does not need to include all properties of the entity - just the ones you want to associate data annotations with.
Reference: EF Database First with ASP.NET MVC: Enhancing Data Validation
You could change view model property with the [DisplayFormat] attribute:
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",
ApplyFormatInEditMode = true)]
public DateTime DeliveredDate { get; set; }
and in your view:
#Html.EditorFor(x => x.DeliveredDate )
or, for displaying the value,
#Html.DisplayFor(x => x.DeliveredDate )
or you can do like this:
#Html.TextBox("MyDate", Model.DeliveredDate .ToLongDateString())

MVC5 with scaffolding; remove time from a datetime field

I am creating an MVC5 project which utilizes scaffolding and has an EDM as a model. I want to use server-side code to remove the time portion of my datetime fields rather than parsing it with JQuery.
How do I achieve this?
Try [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
And if you dont want to validate it use a questionmark after the DateTime property like so public DateTime? Date{ get; set; }
[DisplayName("Date of Birth:")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Display(Order = 35)]
public DateTime? CODoB { get; set; }
or you can just use editfor and display for templates here is a link
You can add EditorTemplate in the view folder, you need to create EditorTemplates folder and then create DateTime.cshtml and there you can pass the DateTime that came from Model to the default editor only the date portion like:#Html.EditorFor(x=>x.Date)
If that is not useful for you you need to tell me, where do you need to trim the time portion only in the view or also in database, and if so is your model code first or DataBase first approach

ASP.NET MVC 5 prevent value changes

When I update my website, it hints me this problem "{"The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.\r\nThe statement has been terminated."}"
The screenshot is list below, there is a value named RecordDate, it has value, but I will not change anything about that value so I didn't display it on the screen.
The problem is MVC automatically update that value for me, and the value of the date becomes 0000-00-01 i think, maybe something else, how to prevent it? just keep the origin value and update other columns.
The model class looks like this
public class ShiftRecord
{
public int ID { get; set; }
public int EmployeeID { get; set; }
[Display(Name="Company Vehicle?")]
[UIHint("YesNo")]
public bool IsCompanyVehicle { get; set; }
[Display(Name="Own Vehicle?")]
[UIHint("YesNo")]
public bool IsOwnVehicle { get; set; }
//Problem comes from this line
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString="{0:yyyy-MM-dd}")]
public DateTime RedordDate { get; set; }
[Display(Name="Day Type")]
public Nullable<DayType> DayType { get; set; }
[Display(Name="Normal Hrs")]
public Nullable<int> NormalHours { get; set; }
[Display(Name="Time and Half Hrs")]
public Nullable<int> TimeAndHalfHours { get; set; }
[Display(Name="Double Time Hrs")]
public Nullable<int> DoubleTimeHours { get; set; }
[Display(Name="Shift Hrs")]
public Nullable<int> ShiftHours { get; set; }
public string Comment { get; set; } // System manager can leave any comment here
public bool IsRead { get; set; } // has this shift record been read
public virtual Employee Employee { get; set; }
public virtual ICollection<JobRecord> JobRecords { get; set; }
}
In the controller, I didn't change anything about the model, so it looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,EmployeeID,IsCompanyVehicle,IsOwnVehicle,RecordDate,DayType,NormalHours,TimeAndHalfHours,DoubleTimeHours,ShiftHours,Comment,IsRead")] ShiftRecord shiftrecord)
{
if (ModelState.IsValid)
{
db.Entry(shiftrecord).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.EmployeeID = new SelectList(db.Employees, "ID", "LastName", shiftrecord.EmployeeID);
return View(shiftrecord);
}
And I didn't change Edit view as well, the only thing is I made RecordDate unchangeable, changed it from #Html.EditorFor to #Html.DisplayFor
<div class="form-group">
#Html.LabelFor(model => model.RedordDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.RedordDate)
#Html.ValidationMessageFor(model => model.RedordDate)
</div>
</div>
Your issue is .net uses a default 1/1/0001 datetime min value, and the sql minimum value is 1/1/1753, which is incompatible. If you use datetime?, it will resolve as null and work OK, or put in code to update the date to a default value before committing to the database.
Your understanding is incorrect. ASP.NET MVC did not automatically update the value for you, the problem arises because you did not post RedordDate to the controller action so RedordDate will have its default value (i.e. default(DateTime)).
DateTime is a value type in .NET such that it cannot be null and its default value is DateTime.MinValue (i.e. 01/01/0001 00:00:00).
You can solve it by making the RedordDate property Nullable by changing its type from DateTime to DateTime? so that it accepts null values.
One thing to note is that if you save this value back to a SQL Server but your underlying SQL datatype is datetime instead of datetime2, you will receive an exception since 01/01/0001 00:00:00 is out-of-range in datetime
Further reading:
MSDN recommends using datetime2 in a new development
Difference between value types and reference types explained by Jon Skeet
You do render any controls for property RedordDate so when you post back, the DefaultModelBinder initializes a new instance of ShiftRecord and RedordDate has a value of DateTime.MinValue (1/1/0001).
Add a hidden control for the property to post it back
#Html.HiddenFor(m => m.RedordDate)
Then in the POST method, remove the [Bind] attribute. Currently, even if the value is posted back, it will not bind because it has been excluded from the Include list. You have RecordDate but not RedordDate (a typo?). Note by default all properties will be bound so the attribute is not necessary unless you are specifically excluding properties.
A better alternative is to create a view model that contains only those properties you want to display and edit (What is a view model in MVC) and then in the POST method, get the original data model and map the view model properties to it.
Side note: Can the vehicle be both IsCompanyVehicle and IsOwnVehicle?

Validating that a Reason field is filled if Date field is today

I use ASP.NET MVC4 in my solution. I have the ViewModel below where I would like to validate that the field EmergencyReason is filled only if the field Date is today. I try this:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIf("Date", Comparison.IsEqualTo, DateTime.Today)]
public string EmergencyReason { get; set; }
...
}
It doesn't work. The third argument of RequiredIf must be a constant expression, ...
Any idea how can I force the user to enter an EmergencyReason only if Date field is today?
Thanks.
You seem to be using some non-standard RequiredIf attribute which is not part of the standard ASP.NET MVC 4 package.
As you know C# allows you to only pass constant values to attributes. So one possibility is to write a custom attribute:
public class RequiredIfEqualToTodayAttribute: RequiredIfAttribute
{
public RequiredIfEqualToTodayAttribute(string field)
: base(field, Comparison.IsEqualTo, DateTime.Today)
{
}
}
and then:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIfEqualToToday("Date")]
public string EmergencyReason { get; set; }
...
}
C# doesn't support DateTime literals, a workaround for this is to use a String like this, but it won't resolve your problem. I suggest you move the validation code inside the Controller and return a ModelState.AddModelError("EmergencyReason", "Emergency Reason is required")

C# serializing Class to XML where one of class properties is DateTime. How to make this property in ISO format?

I'm serializing class which contains DateTime property.
public DateTime? Delivered { get; set; }
After serializing Delivered node contains DateTime formatted like this:
2008-11-20T00:00:00
How can I change this property to make it look like this:
2008-11-20 00:00:00
Thanks in advance
The hack I use for odd formatting during XmlSerialization is to have a special property that is only used during XmlSerialization
//normal DateTime accessor
[XmlIgnore]
public DateTime Delivered { get; set; }
//special XmlSerialization accessor
[XmlAttribute("DateTime")]
public string XmlDateTime
{
get { return this.Delivered.ToString("o"); }
set { this.Delivered = new DateTime.Parse(value); }
}
Take a look at XmlAttributeOverrides class.

Resources