1

I would like to ask is there any way to set an automatic DateTime.Now value for properties ENTRY_DATE and AUDIT_TIME in the Create() HttpPost method? The form is created and it works fine. If the DateTime is inserted manually. But, it won't work if I set an automatic value and would run into a

"One or more validation Error's"..

This is my model (I don't understand how to make a viewmodel) :

public partial class TRRESPONDENT
{
    public TRRESPONDENT()
    {
        this.TRFOLLOWUPRESPONDENTs = new HashSet<TRFOLLOWUPRESPONDENT>();
    }

    [Required(ErrorMessage = "Respondent ID is required!")]
    [Display(Name = "Respondent ID")]
    public string RESPONDENT_ID { get; set; }
    [Required(ErrorMessage = "Please select a BINUS Center!")]
    [Display(Name = "Binus Center")]
    public string BC_ID { get; set; }
    [Required(ErrorMessage = "Name cannot be empty!")]
    [Display(Name = "Name")]
    [StringLength(100,ErrorMessage = "Name length cannot be more than 100 characters!")]
    public string FULL_NAME { get; set; }
    .... // more properties
    [Required(ErrorMessage = "Please pick a City Location!")]
    [Display(Name = "City")]
    public int CITY_ID { get; set; }
    // The following 2 properties need to be set
    [Display(Name = "Entry Date")]
    public DateTime ENTRY_DATE { get; set; }
    public DateTime AUDIT_TIME { get; set; }
    .... 
    public virtual LTCITY LTCITY { get; set; }
    public virtual LTSOURCERESPONDENT LTSOURCERESPONDENT { get; set; }
    public virtual MSBINUSCENTER MSBINUSCENTER { get; set; }
    public virtual ICollection<TRFOLLOWUPRESPONDENT> TRFOLLOWUPRESPONDENTs { get; set; }
}

This is my view

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    @Html.LabelFor(model => model.RESPONDENT_ID)
    @Html.EditorFor(model => model.RESPONDENT_ID)
    @Html.ValidationMessageFor(model => model.RESPONDENT_ID)

    @Html.LabelFor(model => model.BC_ID, "Binus Center")
    @Html.DropDownList("BC_ID", null)
    @Html.ValidationMessageFor(model => model.BC_ID)

    @Html.LabelFor(model => model.FULL_NAME)
    @Html.EditorFor(model => model.FULL_NAME)
    @Html.ValidationMessageFor(model => model.FULL_NAME)

    .... // more form controls

    @Html.LabelFor(model => model.CITY_ID, "City")
    @Html.DropDownList("CITY_ID", null)
    @Html.ValidationMessageFor(model => model.CITY_ID)

    @Html.HiddenFor(model => model.ENTRY_DATE)
    @Html.HiddenFor(model => model.AUDIT_TIME)

    <input type="submit" value="Create" class="btn btn-default" />
}

This is my controller :

public class RespondentController : Controller
{
    private RespondentBINUSEntities db = new RespondentBINUSEntities();

    public ActionResult Create()
    {
        ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", 1);
        var entry = new Models.TRRESPONDENT
        {
            ENTRY_DATE = DateTime.Now,
            AUDIT_TIME = DateTime.Now,
        };
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "RESPONDENT_ID,BC_ID,BINUSIAN_ID,FULL_NAME,EMAIL,PHONE_NUMBER,ADDRESS,CITY_ID,ZIP_CODE,SOURCE_ID,ENTRY_DATE,PACKAGE,AUDIT_USER_NAME,AUDIT_TIME,AUDIT_ACTIVITY")] TRRESPONDENT tRRESPONDENT)
    {
        if (ModelState.IsValid)
        {
            db.TRRESPONDENTs.Add(tRRESPONDENT);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", tRRESPONDENT.CITY_ID);
        return View(tRRESPONDENT);
    }
}
Sion Christian
  • 55
  • 1
  • 12
  • Do you get that validation error during `SaveChanges()` method? What kind of `DateTime.Now` automatic value looks like? – Tetsuya Yamamoto Jan 26 '17 at 04:13
  • You should not be doing that. The value of that property should be set in the controller immediately before you save the object. –  Jan 26 '17 at 04:14
  • yes! when it runs into the db.SaveChanges(), it got error. But if I try to catch the error log with try-catch, the error would occur when I 'throw' the error log. – Sion Christian Jan 26 '17 at 04:14
  • Show the error details there. As Stephen said, property values should be set in controller before passing to `SaveChanges()` method, or use `KeyAttribute` if `no keys defined` error has encountered. – Tetsuya Yamamoto Jan 26 '17 at 04:16
  • @StephenMuecke, I've tried to set the value at controller and/or in my model. But it won't work. It just circle around in my Create form – Sion Christian Jan 26 '17 at 04:16
  • Does the date need to be part of the form if it's always DateTime.Now? Couldn't it be added to the data after it has been posted? – Chad Hedgcock Jan 26 '17 at 04:16
  • Sorry, my mistake. The error will occur if I set @Value inside my form. But, if I set it in controller and/or model, it would just return my Create form over and over again and would not save changes to my database – Sion Christian Jan 26 '17 at 04:18
  • You need to add your code in the question. We cannot guess what mistake you have made (and do not include that property in the form as I noted in your previous question) –  Jan 26 '17 at 04:21
  • It has to be. It should be inserted to the database alongside with the data that the user input – Sion Christian Jan 26 '17 at 04:22
  • _has to be what!_ Show your code! –  Jan 26 '17 at 04:23
  • Since your error related to datetime, I have thoughts with common `The field XXX must be a date` error. However, without detailed code it is hard to tell where the validation error comes from. – Tetsuya Yamamoto Jan 26 '17 at 04:25
  • I have updated the post, guys. Any help would be really appreciated. – Sion Christian Jan 26 '17 at 04:31
  • Now you have just dumpled all your code (90% of which is irrelevant to the question). Which method are you referring to? And which property (I assume its `public DateTime ENTRY_DATE { get; set; }`?) –  Jan 26 '17 at 04:35
  • Well, I see that `ENTRY_DATE` and `AUDIT_TIME` field declared as `DateTime` which may filled with current datetime, but which `SaveChanges()` method exactly throwing validation error? I suspected usage of `EntityState.Modified` triggering it. – Tetsuya Yamamoto Jan 26 '17 at 04:42
  • yes. the property that I'm trying to preset the value is ENTRY_DATE and AUDIT_TIME, Stephen. So, what am I supposed to do, Tetsuya? – Sion Christian Jan 26 '17 at 04:52
  • Can you share the error which you are getting while saving the changes? – Chetan Jan 26 '17 at 04:54
  • Give me 30 min and I will add an answer (and edit your question) –  Jan 26 '17 at 04:54
  • There are 3 `SaveChanges()` method on your code, which one triggered the validation error? If it is `Edit` method, just change the value and save changes made with it (e.g. `ENTRY_DATE = DateTime.Now`), don't re-set the entire entity state as modified one. – Tetsuya Yamamoto Jan 26 '17 at 04:58
  • Chetan, I don't get the error now. But, I'm only circling around in my Create form. – Sion Christian Jan 26 '17 at 04:59
  • Thanks a lot, Stephen. Really appreciated it. I'm working on the create method, Tetsuya.. – Sion Christian Jan 26 '17 at 05:00
  • I don't see any `KeyAttribute` defined there, but it has `HashSet` and `ICollection` which signs Entity Framework model may being used. Could it be `EntityType has no key defined` error? If it's true, just set `KeyAttribute` on `RESPONDENT_ID` and works fine then. – Tetsuya Yamamoto Jan 26 '17 at 05:12
  • @SionChristian, I have added an answer to solve the immediate issue, but I will edit this in a few hours to show how your view model should look, and the associated controller methods –  Jan 26 '17 at 05:17
  • Thank you, Stephen. I really appreciated it. Anyway, do you know how we can generate something like a unique code based on user's selected values? For example if user registers at a dropdownlist that has a value of XBC3, and create it on 2017, then the unique code will be generated maybe like, RXBC3201700010? – Sion Christian Jan 26 '17 at 06:13
  • You need to ask anew question for that (and showing a bit more detail) –  Jan 26 '17 at 06:44

1 Answers1

1

You have not stated the details of the error message, but no doubt this is because you saving a values of 01/01/0001 to a field which which is DATETIME (which only accepts dates between 01/01/1753 to 12/31/9999) and not DATETIME2.

The reason the values of you dates are 01/01/0001 (which is the default for DateTime) is because you do not pass a model to the view so default values are used. The code in your GET needs to be

public ActionResult Create()
{
    ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", 1);
    var entry = new Models.TRRESPONDENT
    {
        ENTRY_DATE = DateTime.Now,
        AUDIT_TIME = DateTime.Now,
    };
    return View(entry); // return your model
}

However you should not use your data model in the view, and instead create a view model containing only the properties you need. Values such as ENTRY_DATE should only be set immediately before you save the data model to the database. For information on a creating a view model, refer What is ViewModel in MVC?.


The basic steps for creating a view model are

  1. Create a new folder (say) ViewModels and copy you data model to and and rename it (say)RespondentVM
  2. Delete all the [Display] attributes from you data model (they are view specific attributes)
  3. Delete all the properties which the user will not be editing in the view (e.g ENTRY_DATE and AUDIT_TIME) except the property which is the objects ID which should be renamed to ID so its automatically bound assuming your using the default routes (note its not clear if you even have an ID property - I assume its RESPONDENT_ID, but that should be an auto-incremented int in the database -i.e. [Key]public int RespondentId { get; set; }). I also recommend you rename all your properties to follow naming conventions - EntryDate, not ENTRY_DATE.
  4. Change all value types to be nullable and add the [Required] attribute to protect against under-posting attacks (e.g. public int CITY_ID { get; set; } becomes public int? CityID { get; set; }
  5. Add additional properties for SelectList's etc that you are currently assigning to ViewBag properties, e.g. public IEnumerable<SelectListItem> CityList { get; set; }

You controller methods will then be

public ActionResult Create()
{
    RespondentVM model = new RespondentVM();
    ConfigureViewModel(model);
    return View(model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RespondentVM model) // note a [Bind]` attribute is not required
{
    if (!ModelState.IsValid)
    {
        ConfigureViewModel(model);
        return View(model);
    }
    // Initialize an instance of your data model and set its properties based on the view model
    TRRESPONDENT respondent = new TRRESPONDENT()
    {
        FULL_NAME = model.FullName,
        CITY_ID = model.CityID,
        ....
        // Set default values
        ENTRY_DATE = DateTime.Now,
        ....
    }
    db.TRRESPONDENTs.Add(respondent);
    db.SaveChanges();
    return RedirectToAction("Index");
}

// Common code for populating SelectLists etc - DRY!
private void ConfigureviewModel(RespondentVM model)
{
    // Note - delete the 4th parameter of the SelectList constructor
    model.CityID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME");
}

And a few extra notes on your view code.

  1. You do not need a hidden input for the ID property if its named ID and your using the default routing
  2. Since you have [Display(Name = "..")] attributes, then in the view its just @Html.LabelFor(m => m.PropertyName), not @Html.LabelFor(m => m.PropertyName, "some text")
  3. To generate your dropdownlists, use @Html.DropDownListFor(m => m.CityID, Model.CityList, "Please select", new { ... }); - you current implementation will not give correct 2-way model binding or client side validation.
Community
  • 1
  • 1
  • See update to the question for how to use a view model (which you should always have, especially when editing data) –  Jan 26 '17 at 07:23