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

Mar*_*ulz 1 c# asp.net-mvc entity-framework data-annotations

我正在使用Entity Framework 的Table Splitting功能来拆分我的实体数据模型,如下所示:

+--------+    +--------------+
|  News  |    |  NewsImages  |
+--------+    +--------------+
| NewsID |    | NewsID       |
| Text   |    | Image        |
+--------+    +--------------+
Run Code Online (Sandbox Code Playgroud)

每个News实体都包含一个名为NewsImage引用相应图像的导航属性.


我正在使用DataAnnotations来验证我的模型.我把[Required]属性上Text的财产News类:

[MetadataType(typeof(NewsValidation))]
public partial class News
{
    /* ... */
}

public class NewsValidation
{
    [Required]
    public string Text { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我用来获取图像数据的服务器端代码:

[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;
}
Run Code Online (Sandbox Code Playgroud)

调用后UpdateNewsImage(news)的方法,所述实体news正确填充与相应的图像数据,但ModelState.IsValid属性仍然false; 调试ModelState.Values导致一个错误:"NewsImage字段是必需的." .


如何在[Required]属性上放置属性(或为每个News实体强制执行图像的其他机制)NewsImage

Rob*_*nik 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;
}
Run Code Online (Sandbox Code Playgroud)

如果模型状态无效,则表示您的状态NewsImage为null.也许你错过了一些明显的东西,其他一些属性使你的模型状态无效.

Asp.net MVC文件数据绑定

我知道了.您似乎认为每次对模型执行某些操作时都会验证模型状态.当然不是这样.在执行操作之前,Asp.net MVC会自动为您验证操作参数.因此,当您处于动作方法体内时,模型状态无效时,无论您对模型​​对象执行何种操作,它都将保持这种状态.除非您手动操作模型状态.在您的情况下,将图像添加到News静止不会更改模型状态(即使您的对象变得有效).

据我所知,你有类型的问题.Asp.net MVC默认模型绑定器能够自动将发布的文件流绑定到HttpPostedFileBase变量.您的NewsImage.Image属性属于类型,byte[]因此不会自动绑定.

问题是您在Web应用程序中使用数据模型实体作为应用程序/视图模型实体,因此您不能只更改NewsImage.Image类型,因为它是EF数据模型的一部分.

为了让这个东西起作用,我认为最好/最简单的方法是用正确的属性类型编写一个单独的视图模型实体类(不要将它与EF数据模型混淆),并添加一个将其转换为数据模型的公共方法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[]
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,您的视图模型对象将按预期正确地进行模型绑定和验证.好的是,由于这种变化,您的代码也会得到简化.ToData()需要从此视图模型对象实例获取数据实体实例时使用方法.当然,您也可以通过提供构造函数来提供对话框,该构造函数接受数据模型实体对象实例并填充视图模型的属性.

如果您使用单独的数据库项目来保存EF数据模型,我建议您将视图模型类严格地放在Web应用程序项目(或任何其他应用程序模型项目)中,因为这是它的使用位置.