-1

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 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 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>
Alex
  • 135
  • 1
  • 15
  • You need to post your code, but I suspect you haven't included a hidden input so the model value is `DateTime.MinValue` when you post back and save. –  Feb 02 '15 at 03:30
  • `@DisplayFor()` does not render a control. When you post back, the model is initialized with the default value for `DateTime` which is `DateTime.MinValue`. One way to solve this is to add `@Html.HiddenFor(m => m.RedordDate)` although I would recommend using view models –  Feb 02 '15 at 03:42
  • I've changed @Html.DisplayFor(model => model.RedordDate) to @Html.HidenFor(model => model.RedordDate), but the problem is not solved, same problem. – Alex Feb 02 '15 at 03:55
  • BTW, I don't want to change the value, for example, the value for the column was "2015-1-1" before update, and after update, it should keep the same value "2015-1-1" – Alex Feb 02 '15 at 03:58
  • 1
    That's the purpose of the hidden input. You post back the original value unchanged. However you also exclude the value from posting back because its not included in your `[Bind(Include="..")]` list (possible typo - "RedordDate" vs "RecordDate"). Since you seem to be wanting to post back every other property, just remove the attribute (every thing is bound by default so its a bit pointless) –  Feb 02 '15 at 04:01
  • Solved! Thank a lot to point out the RedordDate, I don't know why I used that name, and forgive the non-native speaker. – Alex Feb 02 '15 at 04:05

3 Answers3

0

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.

Brian Mains
  • 50,520
  • 35
  • 148
  • 257
  • I use DateTime, but I don't want to change the value. So the problem is MVC automatically update the value for me and I want to prevent it. – Alex Feb 02 '15 at 03:55
  • You can't because you are using DateTime, unless you write a model binder (http://aboutcode.net/2011/03/12/mvc-property-binder.html), or put a hidden field on the form so that a value posts back to the server that's not 1/1/0001. – Brian Mains Feb 02 '15 at 13:29
0

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:

  1. MSDN recommends using datetime2 in a new development
  2. Difference between value types and reference types explained by Jon Skeet
rexcfnghk
  • 14,435
  • 1
  • 30
  • 57
0

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?

Community
  • 1
  • 1