我的问题是:如何在不编写这么多HiddenFors的情况下传递集合和引用的对象类型?
这是我的模特:
public partial class AddressObject
{
public int ID { get; set; }
public string KeyNumber { get; set; }
public int AddressID { get; set; }
public int ObjectTypeID { get; set; }
public double ResidentalArea { get; set; }
public short ResidentsNumber { get; set; }
public Nullable<short> TuristBedsNumber { get; set; }
public virtual Address Address { get; set; }
public virtual ObjectType ObjectType { get; set; }
public virtual ICollection<TrashCan> TrashCans { get; set; }
public virtual ICollection<ObjectOwner> ObjectOwners { get; set; }
}
这是我的观点:
@Html.HiddenFor(model => model.Address.CityID);
@Html.HiddenFor(model => model.Address.Hood);
@Html.HiddenFor(model => model.Address.ID);
@Html.HiddenFor(model => model.Address.Number);
@Html.HiddenFor(model => model.Address.Region);
@Html.HiddenFor(model => model.Address.Street);
@Html.HiddenFor(model => model.Address.City.Addresses);
@Html.HiddenFor(model => model.Address.City.ID);
@Html.HiddenFor(model => model.Address.City.Name);
@Html.HiddenFor(model => model.Address.City.PostalCode);
@Html.HiddenFor(model => model.AddressID);
@Html.HiddenFor(model => model.ObjectOwners);
@Html.HiddenFor(model => model.ObjectType.ID);
@Html.HiddenFor(model => model.ObjectType.Type);
@Html.HiddenFor(model => model.ObjectTypeID);
@Html.HiddenFor(model => model.TrashCans);
@Html.HiddenFor(model => model.TuristBedsNumber);
我不想为地址写一切。我只想传递地址。我的收藏是ObjectOwners。我想做同样的事情。解决方案存在吗?
编辑:我有Controller
及其中的方法ActionResult(AddressObject addressObject)
。在该控制器内部,我正在使用存储库调用unitOfWork
来保存该实体。我的
HiddenFors包含@HtmlBeginForm("Save", "AddressObject")
。当我将模型传递给控制器时,我的地址对象AddressObject.Address
为null = Count 0
。我希望能够使用我引用的对象和集合传递整个对象,而无需为引用的对象或集合的所有属性编写hiddenfors。
EDIT2: 我有一个主要的细节场景(这没关系),文本框绑定到我的View模型的AddressObject。所以我有@ Html.TextBoxFor(m =&gt; m.AddressID)。问题是,当我更改例如AddressObject.TurisBedsNumber时,每个引用的对象或集合都变为null,因此我的AddressObject在使用我更新的属性从View传递回Controller时不是持久的。我希望我的引用和其他属性不会像在更新之前那样触及。我已经尝试过使用Mvc Futures和序列化整个对象和我的对象及其集合和引用的对象都可以。问题是,当我反序列化我的对象时,该对象没有使用新的TuristBedNumber属性更新;它的旧价值。我想知道如何保存我的集合和其他对象的状态。我可以使用HiddenFor帮助程序保存我的状态(写入的属性太多)或者我可以从我的存储库中获取AddressObject或Collection并在我的控制器中更新它;再次,太多的属性。我想能够说&#34;嘿你收藏和我引用的对象,你无论如何都不会改变&#34;。我想将它们全部序列化,但仅限于它们。 有人要求控制器,但这很常见:
public ActionResult(AddressObject addressObject) { unitOfWork.Update(addressObject) }
是的我有ValidState等....
答案 0 :(得分:1)
以下是我用于为属性创建隐藏输入的辅助类。如果属性是复杂类型,则递归调用它以为复杂类型的每个属性创建隐藏输入。在您的情况下,您将使用@ Html.HiddenInputFor(m =&gt; m.Address)生成所有17个输入。请务必在web.config中添加命名空间。
using System;
using System.Collections;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using Sandtrap.Web.Extensions;
namespace Sandtrap.Web.Html
{
/// <summary>
///
/// </summary>
public static class HiddenInputHelper
{
/// <summary>
/// Returns the html for a hidden input(s) of a property.
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="helper"></param>
/// <param name="expression"></param>
/// <param name="includeID">
/// A value indicating the the 'id' attribute should be rendered for the input.
/// </param>
/// <remarks>
/// If the property is a complex type, the methods is called recursively for each property
/// of the type. Collections and complex types with null value (except those with the
/// Required attribute) are ignored.
/// </remarks>
public static MvcHtmlString HiddenInputFor<TModel, TValue>
(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, bool includeID = false)
{
string name = ExpressionHelper.GetExpressionText(expression);
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
StringBuilder html = new StringBuilder();
return MvcHtmlString.Create(HiddenInput(metaData, name, includeID));
}
/// <summary>
/// Returns the html for a hidden input(s) of a property defined by its metadata.
/// The string is not html-encoded.
/// </summary>
/// <param name="metaData">
/// The metadata of the property.
/// </param>
/// <param name="name">
/// The name of the property (rendered as the 'name' attribute).
/// </param>
/// <param name="includeID">
/// A value indicating the the 'id' attribute should be rendered for the input.
/// </param>
/// <remarks>
/// If the property is a complex type, the methods is called recursively for each property
/// of the type. Collections and complex types with null value (except those with the
/// Required attribute) are ignored.
/// </remarks>
public static string HiddenInputForMetadata(ModelMetadata metaData, string name, bool includeID = false)
{
return HiddenInput(metaData, name, includeID);
}
#region .Helper methods
/// <summary>
/// Returns the html for a hidden input(s) of a property.
/// </summary>
/// <param name="metaData">
/// The property metadata.
/// </param>
/// <param name="name">
/// The name of the property (rendered as the 'name' attribute).
/// </param>
/// <param name="includeID">
/// A value indicating the the 'id' attribute should be rendered for the input.
/// </param>
private static string HiddenInput(ModelMetadata metaData, string name, bool includeID)
{
StringBuilder html = new StringBuilder();
if (metaData.ModelType.IsArray && metaData.Model != null)
{
// Primarily for database time stamps, this need to called before checking IsComplexType
// otherwise an endless loop is created
html.Append(HiddenInput(name, Convert.ToBase64String(metaData.Model as byte[]), includeID));
}
else if (metaData.IsComplexType)
{
foreach (ModelMetadata property in metaData.Properties)
{
if (property.IsCollection() && !property.ModelType.IsArray)
{
// This would just render the Count and Capacity property of List<T>
continue;
}
if (property.Model == null && property.ModelType != typeof(string) && !property.IsRequired)
{
// Ignore complex types that are null and do not have the RequiredAttribute
continue;
}
// Recursive call to render a hidden input for the property
string prefix = string.Format("{0}.{1}", name, property.PropertyName);
html.Append(HiddenInput(property, prefix, includeID));
}
}
else
{
html.Append(HiddenInput(name, metaData.Model, includeID));
}
return html.ToString();
}
/// <summary>
/// Returns the html for a hidden input.
/// </summary>
/// <param name="name">
/// The name of the property.
/// </param>
/// <param name="value">
/// The value of the property.
/// </param>
/// <param name="includeID">
/// A value indicating the the 'id' attribute should be rendered for the input.
/// </param>
/// <returns></returns>
private static string HiddenInput(string name, object value, bool includeID)
{
TagBuilder input = new TagBuilder("input");
input.MergeAttribute("type", "hidden");
if (includeID)
{
input.MergeAttribute("id", HtmlHelper.GenerateIdFromName(name));
}
input.MergeAttribute("name", name);
input.MergeAttribute("value", string.Format("{0}", value));
return input.ToString();
}
#endregion
}
}
还需要以下扩展方法
public static bool IsCollection(this ModelMetadata metaData)
{
if (metaData.ModelType == typeof(string))
{
return false;
}
return typeof(IEnumerable).IsAssignableFrom(metaData.ModelType);
}