4

I have a EF Code First setup, I have a particular column that is marked as Required via annotation. This column has a default value constraint specified in the database.

What I'm trying to do is allow the user to enter the value on a form but if they omit it, use the default value from the database. I'm not having any luck.

If I don't enter anything, the Required error shows on the form. If I add [DatabaseGenerated(DatabaseGeneratedOption.Computed)] annotation, the value the user enters is ignored and it always uses the database default.

Sampath
  • 63,341
  • 64
  • 307
  • 441
Brad
  • 1,684
  • 4
  • 20
  • 36
  • 1
    The `[Required]` attribute does not make much sense in this case. If you have a default value, there is no point "pretending" the field to be mandatory. – Kosala W Aug 25 '16 at 05:18
  • I agree with you, but because this is a string, if I don't specify [Required] the varchar field becomes nullable in the database (which I don't want). – Brad Aug 25 '16 at 12:08
  • 1
    This is a known issue in EF. As far as I know this is fixed in EF 7. Refer https://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2929682-support-database-default-values-in-code-first. At the moment your only choice is to declare a "default constraint" using TSQL. Sorry, I thought you knew about it already. – Kosala W Aug 25 '16 at 22:46
  • @Brad why you're not giving any feedback about the below solutions ? tell us ,we can remove it if it's not helpful to you. – Sampath Aug 26 '16 at 00:55
  • @Sampath Because neither of the answers are acceptable answers. – Brad Aug 26 '16 at 01:03
  • @Brad Then you have to mention about it.Otherwise no one will put a new answer for you. – Sampath Aug 26 '16 at 01:09

2 Answers2

0

What you can do is perform the magic while parsing form values.

When checking for the specific column's user input from the form, check the column using

if (!String.IsNullOrWhiteSpace(value))
    //set the value in the database entry based on user's input

The above piece of code only enters a value into the database if something has been entered on the form.

This solution only works if you are able to parse the form's values after user 'submits'.

Keyur PATEL
  • 2,299
  • 1
  • 15
  • 41
0

This was my solution to this issue, which is not great, but manageable.

In my model, I annotated the property with:

[DefaultValueSql("'A'")]
[DefaultValue("A")]
[Required]

The DefaultValueSql is a custom attribute that handles the creation of SQL default column values when doing migrations. The DefaultValue matches that value. I'm aware this is a violation of DRY, but using this solution removes the need for the default in the database anyway (I'll probably remove it in the future).

In my Controller, on the Create/Edit ActionResult post handlers I added this:

    if (model.ActiveIndicator == null)
    {
        model.ActiveIndicator = ((DefaultValueAttribute)(model.GetType().GetProperty("ActiveIndicator").GetCustomAttributes(typeof(DefaultValueAttribute), true).First())).Value.ToString();
        ModelState["ActiveIndicator"].Errors.Clear(); // Removes Model Error
    }

This sets the default to the DefaultValue listed in the annotation and removes the ModelState error for this property allowing the ModelState.IsValid to be true.

This solution works well for string defaults, however non-string (types that can't be null), should probably be done differently, perhaps in the model class constructor.

Edit: If you are using TryUpdateModel, you must set the ModelState value instead of the submitted model value:

    if (model.ActiveIndicator == null)
    {
        var defValue = ((DefaultValueAttribute)(model.GetType().GetProperty("ActiveIndicator").GetCustomAttributes(typeof(DefaultValueAttribute), true).First())).Value.ToString();
        ModelState.SetModelValue("ActiveIndicator", new ValueProviderResult(defValue, "", CultureInfo.InvariantCulture));
        ModelState["ActiveIndicator"].Errors.Clear(); // Removes Model Error
    }
Brad
  • 1,684
  • 4
  • 20
  • 36