2009-02-18 3 views
4

Учитывая следующие модели,ASP.NET MVC UpdateModel пустое свойство

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

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

вид,

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

и контроллер

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

мой экземпляр б будет содержать свойство с пустая строка для Name.

Есть ли в любом случае, чтобы UpdateModel установил свойство A равным null, если для имени не было введено никаких значений?

Чтобы прояснить, это простой случай, мой сценарий реального мира содержит модели данных с сотнями свойств этого файла. Определение этих моделей данных не в моих силах. Поэтому мне нужно решение для общего случая, т. Е. Не создавать свойство, если значения не были введены.

Дальнейшие разъяснения: мне нужно, чтобы это работало и в сценариях редактирования, то есть экземпляр b с именем A.Name, установленным в «foo», редактируется, чтобы установить A.Name в «», я хочу, чтобы A был нулевым.

ответ

5

Я только что обнаружил это поведение (случайно благодаря ограничению проверки), и я думаю, что это ошибка. Интересно, сколько разработчиков теперь ненамеренно сохраняют пустые строки в свой db вместо null? :-)

В любом случае, я собираюсь изучить это еще немного и посмотреть, есть ли лучшее решение.

Update:

Вот решение:

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); 
    } 
    } 
} 

И в Application_Start поставить это:

ModelBinders.Binders.DefaultBinder = new EmptyStringToNullModelBinder(); 
2

UpdateModel инициализирует свойство, когда это свойство находится в FormCollection. Чтобы не допустить, чтобы UpdateModel установил некоторые свойства в пустые значения, вы можете удалить все элементы из вашего FormCollection, где значение пусто. Для этого вы можете добавить метод расширения к типу NameValueCollection.

+0

Что делать, если я редактирую экземпляр B, который уже имеет экземпляр InstanceOfA.Name? Я предполагаю, что он сохранит исходное значение. – Neil

+0

Если вы не удалите текст из «Html.TextBox (« A.Name »), он будет опубликован. Если экземпляр B имеет экземпляр A с пустым именем, то текстовое поле будет пустым и в результате этот элемент будет удален во время публикации, и значение не изменится на null. – zihotki

2

Представляется, что ASP.NET MVC 2 Preview 1 будет делать это для вас при созданииобъектива.

ie. конвертировать автоматически? Foo = & Bar = кошке

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

Я предпочитаю, чтобы получить пустую строку над нулем, так что я не уверен, но если его окончательный дизайн, но там, похоже, изменение.

3

Это родственное отношение, и я подумал, что это может помочь тем, кто каким-то образом достиг этой страницы. Я работаю с ASP.NET MVC 3, и в этой версии, когда пустое текстовое поле отправляется на сервер, оно привязано как null к модели.

Мне пришлось написать противоположное связующее устройство, которое меняет нулевые строки на пустые строки.

Я взял вышеуказанный код Andrew Peters (спасибо за это!) И изменил его на следующее.

вещи заметить:

  1. Как уже упоминалось - это модель связующего делает противоположное.
  2. Вместо того, чтобы проверять тип значения, я проверяю его с помощью свойстваDescriptor, что, я думаю, лучше, потому что это его цель - описать значение. В моем случае это важно, потому что я не могу проверить значение, которое является нулевым. Через дескриптор я могу найти все, что мне нужно.

А вот код:

public sealed class CustomModelBinder : DefaultModelBinder 
{ 
    protected override void SetProperty(ControllerContext controllerContext, 
     ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value) 
    { 
     if (value == null && propertyDescriptor.PropertyType == typeof(string)) 
      value = string.Empty; 

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

Я надеюсь, что это поможет кому-то.

0

Спасибо за ваш ответ, я немного изменил его, чтобы изменить не все свойства строки, а также свойства, которые не являются строкой, также могут быть изменены. Благодаря DefaultValueAttribute.

public class DefaultValueModelBinder: DefaultModelBinder 
{ 
    protected override void SetProperty(ControllerContext controllerContext, 
             ModelBindingContext bindingContext, 
             PropertyDescriptor propertyDescriptor, 
             object value) 
    { 
    if(value == null) 
    { 
     var defaultValue = (DefaultValueAttribute)propertyDescriptor.Attributes[ typeof(DefaultValueAttribute) ]; 
     if(defaultValue != null) 
     value = defaultValue.Value; 
    } 

    base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value); 
    } 
} 
Смежные вопросы