这是我在StackOverflow上的第一篇文章。我希望这是有用的。
我有一个Razor视图,旨在允许编辑包含预定义值或空值的模型的可显示属性。视图不应该改变模型属性的内容,除非用户在基于视图的UI中有意地修改它们。除了包含图像数据的类型为byte[]
的属性之外,视图的行为正确:Model.ImageData
@using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" } ))
{
@Html.EditorForModel()
<div class="editor-label">Image</div>
<div class="editor-field">
@if (Model.ImageData == null)
{
@: No image has been assigned in the database.
}
else
{
<img width="150" height="150" src="@Url.Action("GetImage", "Product", new { Model.ID} )" />
}
<div>Upload new image: <input type="file" name="Image" /></div>
</div>
<input type="submit" value="Save" />
}
上述视图适用于模型中除Model.ImageData
外的所有属性。在这种情况下,发布将导致任何先前设置的Model.ImageData
设置为空。我已经确认Model.ImageData
在发布期间被设置为null,通过验证在发布之前,Model.ImageData
包含一个有效的字节数组(具有预期的图像)。
上述视图的控制器代码为:
public ViewResult Edit(int id)
{
Product product = repository.Products.FirstOrDefault(p => p.ID == id);
// breakpoint here shows that all model properties including product.ImageData are populated and valid.
return View(product);
}
[HttpPost]
public ActionResult Edit(Product product, HttpPostedFileBase Image)
{
if (ModelState.IsValid)
{
// breakpoint here shows that product.ImageData is null (but all other model properties are still populated with data).
if (Image != null)
{
product.ImageMimeType = Image.ContentType;
product.ImageData = new byte[Image.ContentLength];
Image.InputStream.Read(product.ImageData, 0, Image.ContentLength);
}
repository.SaveProduct(product);
TempData["Message"] = string.Format("{0} has been saved", product.Name);
return RedirectToAction("Index");
}
else
{
return View(product);
}
}
下面是更新模型的责任代码(尽管在调用此代码之前模型正在更改):
public void SaveProduct(Product product)
{
if (product.ID == 0)
{
context.Products.Add(product); // why doesn't this try to save ID = 0 to the ID field of the product in the database??
}
else
{
Product dbEntry = context.Products.Find(product.ID);
if (dbEntry != null)
{
dbEntry.Name = product.Name;
dbEntry.Description = product.Description;
dbEntry.Category = product.Category;
dbEntry.Price = product.Price;
dbEntry.ImageData = product.ImageData;
dbEntry.ImageMimeType = product.ImageMimeType;
}
}
context.SaveChanges();
}
我做错了什么?
这确实是您应该考虑使用ViewModel
类的地方。但是,为了保持当前的做事方式,尽量减少更改,请尝试将SaveProduct()
方法修改为以下内容:
public void SaveProduct(Product product, bool updateImage = false)
{
context.Products.Attach(product);
// mark product as modified
var entry = context.Entry(product);
entry.State = EntityState.Modified;
entry.Property(e => e.ImageData).IsModified = updateImage;
entry.Property(e => e.ImageMimeType).IsModified = updateImage;
context.SaveChanges();
}
,将控制器代码修改为:
...
var updateImage = false;
if (Image != null)
{
updateImage = true;
product.ImageMimeType = Image.ContentType;
product.ImageData = new byte[Image.ContentLength];
Image.InputStream.Read(product.ImageData, 0, Image.ContentLength);
}
repository.SaveProduct(product, updateImage);
....