将数据注释添加到由实体框架生成的类


93

我有以下由实体框架生成的类:

public partial class ItemRequest
{
    public int RequestId { get; set; }
    //...

我想将此设为必填字段

[Required]
public int RequestId { get;set; }

但是,由于这是生成的代码,因此将被清除。我无法想象创建局部类的方法,因为该属性是由生成的局部类定义的。如何以安全的方式定义约束?


如果您的属性为int,则默认情况下modelbinder是必需的,因此您的[Required]属性不会在此处添加任何内容。
Kirill Bestemyanov 2013年

@KirillBestemyanov-@ Html.ValidationMessageFor(model => model.Item.Item.ResourceTypeID)应该会使客户端失败。它不是。
P.Brian.Mackey,

Answers:


143

生成的类ItemRequest将始终是一个partial类。这使您可以编写第二部分类,该部分类带有必要的数据注释。在您的情况下,分部类ItemRequest如下所示:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

//make sure the namespace is equal to the other partial class ItemRequest
namespace MvcApplication1.Models 
{
    [MetadataType(typeof(ItemRequestMetaData))]
    public partial class ItemRequest
    {
    }

    public class ItemRequestMetaData
    {
        [Required]
        public int RequestId {get;set;}

        //...
    }
}

11
局部类将不会重新生成。这就是为什么将其定义为局部的原因。
MUG4N 2014年

您是否错过了偏偏修饰符?您是否使用相同的名称空间?
MUG4N

3
.NET Core用户:使用ModelMetadataType代替MetadataType。
Bob Kaufman

1
只要名称空间相同
分部

40

正如MUG4N回答的那样,您可以使用部分类,但最好使用接口。在这种情况下,如果EF模型与验证模型不对应,则会出现编译错误。因此,您可以修改EF模型,而不必担心验证规则已过时。

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

namespace YourApplication.Models
{
    public interface IEntityMetadata
    {
        [Required]
        Int32 Id { get; set; }
    }

    [MetadataType(typeof(IEntityMetadata))]
    public partial class Entity : IEntityMetadata
    {
        /* Id property has already existed in the mapped class */
    }
}

PS:如果您使用的项目类型不同于ASP.NET MVC(在执行手动数据验证时),请不要忘记注册验证器

/* Global.asax or similar */

TypeDescriptor.AddProviderTransparent(
    new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));

@dimonser不错的解决方案,我也尝试添加这样的xml注释(对于那些需要在代码中稍作解释的DB字段-即以intellitype显示),但是它似乎不起作用。任何想法如何做到这一点?
珀西

@Rick,您好,您可以在interface属性上添加注释,但是只有在使用interface变量时,您才能看到它。或者,您可以在局部类中添加评论。在这种情况下,使用类的实例时将看到它。没有其他可用的案例。因此,您可以同时使用它们来覆盖所有情况。在第一种情况下,您可以描述字段验证规则,在第二种情况下,请尝试描述目的
dimonser 2015年

答案是经过深思熟虑的,但是如果验证不再与自动生成的实体框架类同步,则我更希望看到编译错误。我正在努力思考一种情况,您可能想验证实体框架类中不再存在的属性。
迈克,

1
这对我不起作用,它说我需要实现IEntityMetadata接口...
Worthy7

14

我找到了类似于MUG4N答案的解决方案,但是,将MetaData类嵌套在实体类中,从而减少了公共命名空间列表中类的数量,并消除了为每个元数据类使用唯一名称的麻烦。

using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models 
{
    [MetadataType(typeof(MetaData))]
    public partial class ItemRequest
    {
        public class MetaData
        {
            [Required]
            public int RequestId;

            //...
        }
    }
}

我在整个项目中一直在使用它。组织起来容易得多。[NotMapped]当我需要它们时,我也会在部分类中添加自定义属性。
卡特梅德林

5

这是@dimonser答案的一种扩展,如果您重新生成数据库模型,则必须手动在这些类上重新添加接口。

如果您有胃,也可以修改.tt模板:

这是在某些类上自动生成接口的示例,这.tt只是EntityClassOpening您后面的replace 方法的片段(显然var stringsToMatch是您的实体名称和接口)。

public string EntityClassOpening(EntityType entity)
{
    var stringsToMatch = new Dictionary<string,string> { { "Answer", "IJourneyAnswer" }, { "Fee", "ILegalFee" } };
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}{4}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
        stringsToMatch.Any(o => _code.Escape(entity).Contains(o.Key)) ? " : " + stringsToMatch.Single(o => _code.Escape(entity).Contains(o.Key)).Value : string.Empty);
}

但是,任何普通人都不应该对自己这样做,圣经已证明有人为此而去。


2

我不确定该怎么做,但是有办法解决。通过重写自定义DataAnnotationsModelValidatorProvider的GetValidators进行动态数据验证。在其中,您可以阅读验证每个字段的规则(来自数据库,配置文件等),并根据需要添加验证器。它具有附加值,您的验证不再与模型紧密耦合,并且可以更改而无需重新启动站点。当然,这可能对您的情况有些大材小用,但对我们来说是理想选择!


我们在首次实现此结构时就做了。从那以后,我们转而使用NHibernate,但这与解决方案无关。我们的验证代码无需更改就可以正常工作(仅更改了数据访问层)。
JTMon

1

修改T4模板并添加所需的注释,此文件通常名为MODELNAME.tt

查找T4在哪里创建类和方法,以了解将它们放在哪里。

     <#=codeStringGenerator.IgnoreJson(navigationProperty)#>


//create this method in file
public string IgnoreJson(NavigationProperty navigationProperty){
            string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore]
    [IgnoreDataMember]";

            return result;
        }

您还需要添加名称空间。

<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;

通过保存模型来重建类,所有方法都应添加注释。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.