Я знаю, что эта ветка устарела, но подумала, что возродю ее, чтобы получить обратную связь с моим решением.
Я нахожусь в аналогичной ситуации, когда мои объекты передаются в представление, и представление может отображать только часть этого объекта для редактирования. Очевидно, что когда контроллер получает модель обратно из подшивки модели по умолчанию, а значения, не отправленные обратно, становятся нулевыми ... и сохранение этого означает, что значение БД становится нулевым только потому, что оно не отображалось / не возвращалось из представления.
Мне не понравилась идея создания модели для каждого вида. Я знаю, что это, вероятно, правильный способ ... но я искал шаблон многократного использования, который можно было бы реализовать довольно быстро.
См. Метод «MergeWith» ... так как он будет использован для получения копии объекта из базы данных и объединения ее с копией, возвращенной из представления (отправлено обратно)
namespace SIP.Models
{
[Table("agents")]
public class Agent
{
[Key]
public int id { get; set; }
[Searchable]
[DisplayName("Name")]
[Column("name")]
[Required]
[StringLength(50, MinimumLength = 4)]
public string AgentName { get; set; }
[Searchable]
[DisplayName("Address")]
[Column("address")]
[DataType(DataType.MultilineText)]
public string Address { get; set; }
[DisplayName("Region")]
[Searchable]
[Column("region")]
[StringLength(50, MinimumLength = 3)]
public string Region { get; set; }
[DisplayName("Phone")]
[Column("phone")]
[StringLength(50, MinimumLength = 4)]
public string Phone { get; set; }
[DisplayName("Fax")]
[Column("fax")]
[StringLength(50, MinimumLength = 4)]
public string Fax { get; set; }
[DisplayName("Email")]
[RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
[Column("email")]
[StringLength(50, MinimumLength = 4)]
public string Email { get; set; }
[DisplayName("Notes")]
[Column("notes")]
[DataType(DataType.MultilineText)]
public string Notes{ get; set; }
[DisplayName("Active")]
[Column("active")]
public bool Active { get; set; }
public override string ToString()
{
return AgentName;
}
public bool MergeWith(Agent a, string[] fields)
{
try
{
foreach (PropertyInfo pi in this.GetType().GetProperties())
{
foreach (string f in fields)
{
if (pi.Name == f && pi.Name.ToLower() != "id")
{
var newVal = a.GetType().GetProperty(f).GetValue(a,null);
pi.SetValue(this, newVal, null);
}
}
}
}
catch (Exception ex)
{
return false;
//todo: Log output to file...
}
return true;
}
}
}
И чтобы использовать это в контроллере .. у вас будет что-то вроде ..
[HttpPost]
public ActionResult Edit(Agent agent)
{
if (ModelState.IsValid)
{
Agent ag = db.Agents.Where(a => a.id == agent.id).ToList<Agent>().First<Agent>();
ag.MergeWith(agent, Request.Params.AllKeys);
db.Entry(ag).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(agent);
}
Таким образом, во время обратной отправки он берет объект из базы данных и обновляет его, используя объект из поля зрения ..., но обновляет только те значения, которые были отправлены обратно. Так что если у вас есть поле типа "адрес" или что-то, что не появляется в представлении .. это не затрагивается во время обновления.
Я проверял это до сих пор, и я работаю для своих целей, поэтому я приветствую любые отзывы, так как я стремлюсь увидеть, как другие преодолели эту ситуацию. Это первая версия, и я уверен, что ее можно реализовать лучше, например, с помощью метода расширения или чего-то еще ... но сейчас MergeWith можно копировать / вставлять в каждый объект модели.