使用System.ComponentModel.DataAnnotations和Entity Framework 4.0

52

我正在使用MVC3,并将Entity Framework 4.0实体用作我的模型。 到目前为止,就使用它作为模型而言,一切都很好(所有的crud操作/页面生成都可以直接使用)。 我想知道的是,当您手动生成模型时,如何获得相同的强大标签和验证信息?

这是示例MVC3项目生成的类:

public class LogOnModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

通过上面的示例,您可以指定为字段呈现什么内容(显示)以及使用哪种类型的字段(密码)。然而,当我尝试使用实体框架并将其推送到下面的视图时,我发现自动生成的标签只是字段名称,并不是我希望用户看到/阅读的任何内容:

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Person</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.MiddleName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MiddleName)
            @Html.ValidationMessageFor(model => model.MiddleName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Birthdate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Birthdate)
            @Html.ValidationMessageFor(model => model.Birthdate)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>}

enter image description here

我的问题是:如何为使用EF4生成的实体添加额外的装饰?除了System.ComponentModel.DataAnnotations之外,我还应该使用什么?我知道实体会重新生成,直接向实体代码添加可能不是一个好主意,但出于某种原因,我想不到比在视图中手动输入标签文本更好的方法(这很糟糕,在MVC中不需要这样做!)。 我希望保持应用程序足够动态,能够为我的模型提供正确的显示信息并保持MVC方法。我该怎么做?


相关链接:https://dev59.com/WHA75IYBdhLWcg3w-OZA - James Skemp
将元数据类嵌套在部分类中是一个好主意,但不幸的是,Entity Framework总是会覆盖它...我正在使用MVC5,并且将其放在同一文件夹但不同类中的第一个解决方案运行良好。 - Mohamed_Essa
类似这样的代码也可以工作:#if !NET40 using System.ComponentModel.DataAnnotations; #endif /* 在此处编写您的代码 / #if !NET40 [StringLength(256)] #endif / MVC / DB 模型定义 */ - Ivan Silkin
3个回答

83

我没有为ASP.NET MVC(只针对Silverlight)做过这个,但我相信相同的原则适用。你可以创建一个“元数据伙伴类”,因为EF生成的类型应该是partial的,因此你可以在它们上面添加一些内容(如MetadataTypeAttribute),然后创建这个兄弟类来保存元数据。

这种方法有点丑陋,但应该可行。具体步骤如下(假设EF实体的名称为“Person”):

[MetadataType(typeof(PersonMetadata))]
public partial class Person { 
  // Note this class has nothing in it.  It's just here to add the class-level attribute.
}

public class PersonMetadata {
  // Name the field the same as EF named the property - "FirstName" for example.
  // Also, the type needs to match.  Basically just redeclare it.
  // Note that this is a field.  I think it can be a property too, but fields definitely should work.

   [Required]
   [Display(Name = "First Name")]
  public string FirstName;
}

1
优秀的回答 - 但是有人知道如何将其集成到t4模板中吗? - Raithlin
1
@Raithlin: 你也可以从这里受益:http://t4metadatatemplate.codeplex.com/ - Leniel Maccaferri
2
你可以使用接口IPersonMetaData替换PersonMetadata,并让Person实现它,这样如果字段名不正确就会导致编译错误。 - Kek
只是为了确认一下:如果需要的话,您可以使用“属性”而不是“字段”,就像您在代码注释中暗示的那样。 - Nick
为什么如果我使用元数据类,Validator.TryValidateObject 总是返回 true? - cpiock
显示剩余7条评论

2

以下是所有细节的内容,它可以工作。

在这里输入图片描述

在这里输入图片描述

在这里输入图片描述

在这里输入图片描述

这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace Validate.Models
{
    [MetadataType(typeof(PersonMetadata))]
    public partial class Person
    {
        // Note this class has nothing in it.  It's just here to add the class-level attribute.
    }

    public class PersonMetadata
    {
        // Name the field the same as EF named the property - "FirstName" for example.
        // Also, the type needs to match.  Basically just redeclare it.
        // Note that this is a field.  I think it can be a property too, but fields definitely should work.

        [Required]
        [Display(Name = "Enter Your Name")]
        public string FirstName;
    }
}

2

Austin Lamb 所说的那样,但是将 MetaData 类嵌套在实体类中,从而减少公共命名空间列表中的类数量,并消除每个元数据类需要独特名称的需求。

using System.ComponentModel.DataAnnotations;

namespace Validate.Models
{
    [MetadataType(typeof(MetaData))]
    public partial class Person
    {
        public class MetaData
        {
            [Required]
            [Display(Name = "Enter Your Name")]
            public string FirstName;

            //...
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接