views:

1989

answers:

3

Given the following Model,

public class A
{
 public string Name { get; set; }
}

public class B
{
 public string Address { get; set; }
 public A InstanceOfA { get; set; }
}

View,

<%= Html.TextBox("A.Name") %>

and Controller

UpdateModel<B>(b, collection.ToValueProvider());

my b instance will contain a property of A with an empty string for Name.

Is there anyway to have UpdateModel set the A property to null if no value has been entered for name?

To clarify, this is a simple case, my real world scenario contains data models with hundreds of properties of this ilk. The definition of these data models is out of my hands. Therefore I need a solution for the general case, ie don't create a property if no values have been entered.

Further clarification: i need this to work in edit scenarios aswell, i.e. an instance of b with A.Name set to "foo" is edited to set A.Name to "", i want A to be null.

+3  A: 

UpdateModel initialize a property when this property is in the FormCollection. In order to prevent UpdateModel from setting some properties to empty values you can delete all items from your FormCollection where value is empty. To do this you can add an extension method to the NameValueCollection type.

zihotki
What if I edit an instance of B that already has InstanceOfA.Name set? I'm assuming it will keep the original value.
Neil
If you'll not delete text from "Html.TextBox("A.Name")" it will be posted. If instance of B has instance of A with empty name then textbox will be empty and as a result this item will be removed during post and the value will not change to null.
zihotki
+4  A: 

I just discovered this behavior (by accident thanks to a check constraint) and I think it is a mistake. I wonder how many devs are now inadvertently saving empty strings into their db instead of null? :-)

Anyway, I'm going to explore this a bit more and see if there is a better solution.

Update:

Here is a solution:

using System.ComponentModel;
using System.Web.Mvc;

namespace CustomerWebsite.Mvc
{
  public sealed class EmptyStringToNullModelBinder : DefaultModelBinder
  {
    protected override void SetProperty(ControllerContext controllerContext,
      ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    {
      if ((value != null)
          && (value.GetType() == typeof(string)
              && ((string)value).Length == 0))
      {
        value = null;
      }

      base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
    }
  }
}

And in Application_Start put this:

ModelBinders.Binders.DefaultBinder = new EmptyStringToNullModelBinder();
Andrew Peters
+1  A: 

It appears that ASP.NET MVC 2 Preview 1 will do this for you when doing modelbinding.

ie. convert automatically ?Foo=&Bar=cat to

model.Foo = null;
model.Bar = "cat":

I actually prefer to get an empty string over a null so I'm not sure yet if its the final design but there does seem to be a change.

Simon_Weaver