拆分实体数据模型属性的数据注释[必需]属性

时间:2011-01-31 11:53:01

标签: c# asp.net-mvc entity-framework data-annotations

我正在使用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实体强制执行图像的其他机制)?

1 个答案:

答案 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文件数据绑定

我明白了。您似乎认为每次对模型执行某些操作时都会验证模型状态。当然不是这样。在执行操作之前,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应用程序项目(或任何其他应用程序模型项目)中,因为它就是使用它的位置。