我正在使用Entity Framework的 Table Splitting 功能将我的实体数据模型拆分如下:
+--------+ +--------------+
| News | | NewsImages |
+--------+ +--------------+
| NewsID | | NewsID |
| Text | | Image |
+--------+ +--------------+
每个News
实体都包含一个名为NewsImage
的导航属性,用于引用相应的图像。
我正在使用 DataAnnotations 来验证我的模型。我将[Required]
属性放在Text
类的News
属性上:
[MetadataType(typeof(NewsValidation))]
public partial class News
{
/* ... */
}
public class NewsValidation
{
[Required]
public string Text { get; set; }
}
这是我用来获取图像数据的服务器端代码:
[HttpPost]
public ActionResult Create(News news)
{
if (ModelState.IsValid)
{
UpdateNewsImage(news);
_newsRepository.Add(news);
_newsRepository.SaveChanges();
return RedirectToAction("Index");
}
}
private void UpdateNewsImage(News news)
{
byte[] newsImage = GetNewsImage();
news.NewsImage = new NewsImage { Image = newsImage };
}
private byte[] GetNewsImage()
{
foreach (string upload in Request.Files)
{
HttpPostedFileBase uploadedFile = Request.Files[upload];
if (!uploadedFile.HasFile())
{
break;
}
Stream fileStream = uploadedFile.InputStream;
int fileLength = uploadedFile.ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
return fileData;
}
return null;
}
调用UpdateNewsImage(news)
方法后,实体news
正确填充并包含相应的图片数据,但ModelState.IsValid
属性仍为false
;调试ModelState.Values
导致一个错误:“需要NewsImage字段。”。
如何在[Required]
属性上放置News
属性(或对每个NewsImage
实体强制执行图像的其他机制)?
答案 0 :(得分:6)
为什么不在验证类中的[Required]
属性上放置NewsImage
属性?这将使News
实体实例也需要具有相应的NewsImage
实体实例。
将RequiredAttribute放在引用(如在非字符串中)类型属性时,它仅检查该属性是否为null。让我通过RequiredAttribute.IsValid()
方法支持这个:
public override bool IsValid(object value)
{
if (value == null)
{
return false;
}
string str = value as string;
if (str != null)
{
return (str.Trim().Length != 0);
}
return true;
}
如果模型状态无效,则表示您的NewsImage
为空。也许你错过了一些明显的东西,其他一些属性使你的模型状态无效。
我明白了。您似乎认为每次对模型执行某些操作时都会验证模型状态。当然不是这样。在执行操作之前,Asp.net MVC会自动为您验证操作参数。因此,当您处于动作方法体内时,模型状态无效时,无论您对模型对象执行何种操作,它都将保持这种状态。除非您手动操作模型状态。在您将图像添加到News
的情况下,仍然不会更改模型状态(即使您的对象有效)。
据我所知,你有类型的问题。 Asp.net MVC默认模型绑定器能够自动将发布的文件流绑定到HttpPostedFileBase
个变量。 <{1}}属性的类型为NewsImage.Image
,因此不会自动绑定。
问题是您在Web应用程序中使用数据模型实体作为应用程序/视图模型实体,因此您不能只更改byte[]
类型,因为它是EF数据模型的一部分。
为了让这个东西工作,我想最好/最简单的方法是用正确的属性类型编写一个单独的视图模型实体类(不要将它与EF数据模型混淆),并添加一个转换它的公共方法到数据模型NewsImage.Image
实体。
News
因此,您的视图模型对象将按预期正确地进行模型绑定和验证。好的是,由于这种变化,您的代码也会得到简化。需要从此视图模型对象实例获取数据实体实例时,请使用namespace WebProject.ViewModels
{
public class News
{
public int Id { get; set; } // not used when creating new entries but used with editing/deleting hens not being required
[Required]
public string Text { get; set; }
[Required]
public HttpPostedFileBase Image { get; set; }
public Data.News ToData()
{
return new Data.News {
Id = this.Id,
Text = this.Text,
NewsImage = new Data.NewsImage {
Id = this.Id,
Image = // convert to byte[]
}
}
}
}
}
方法。当然,您也可以通过提供一个构造函数来提供对话框,该构造函数接受数据模型实体对象实例并填充视图模型的属性。
如果您使用单独的数据库项目来保存EF数据模型,我建议您将视图模型类严格地放在Web应用程序项目(或任何其他应用程序模型项目)中,因为它就是使用它的位置。