给实体框架生成的类添加数据注解

Posted

技术标签:

【中文标题】给实体框架生成的类添加数据注解【英文标题】:Add data annotations to a class generated by entity framework 【发布时间】:2013-05-20 03:28:47 【问题描述】:

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

public partial class ItemRequest

    public int RequestId  get; set; 
    //...

我想将此设为必填字段

[Required]
public int RequestId  get;set; 

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

【问题讨论】:

如果您的属性是 int,则默认情况下它是 modelbinder 必需的,因此您的 [Required] 属性不会在此处添加任何内容。 @KirillBestemyanov - @html.ValidationMessageFor(model => model.Item.Item.ResourceTypeID) 应该在客户端失败。它没有。 【参考方案1】:

生成的类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;

        //...
    

【讨论】:

不会重新生成部分类。这就是为什么它被定义为部分的原因。 你错过了部分修饰符吗?你使用相同的命名空间吗? .NET Core 用户:使用 ModelMetadataType 而不是 MetadataType。 只要命名空间相同,你就可以将部分类放在任何你想要的地方【参考方案2】:

正如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 */
    

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

/* Global.asax or similar */

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

【讨论】:

@dimonser 不错的解决方案,我也尝试添加这样的 xml cmets(对于那些需要在代码中稍加解释的数据库字段 - 即以智能型显示),但它似乎不起作用.知道该怎么做吗? 嗨@Rick,您可以在接口属性上添加注释,但只有在使用接口变量时才能看到它。或者您可以在部分类中添加评论。在这种情况下,您将在使用类的实例时看到它。没有其他可用的案例。所以你可以同时使用它们来涵盖所有情况,在第一种情况下你可以描述字段验证规则,在第二种情况下尝试描述目的 经过深思熟虑的答案,但如果验证不再与自动生成的实体框架类同步,我更愿意看到编译错误。我很难想到您可能想要验证实体框架类中不再存在的属性的情况。 这对我不起作用,它说我需要实现 IEntityMetadata 接口...【参考方案3】:

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

using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models 

    [MetadataType(typeof(MetaData))]
    public partial class ItemRequest
    
        public class MetaData
        
            [Required]
            public int RequestId;

            //...
        
    

【讨论】:

我在整个项目中一直在使用它。更容易组织。当我需要它们时,我也会在部分类中使用[NotMapped] 添加自定义属性。【参考方案4】:

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

如果你有胃口,你也可以修改你的.tt模板:

这是在某些类上自动生成接口的示例,这是来自.tt 的片段,只需将您的EntityClassOpening 方法替换为以下(显然var stringsToMatch 使用您的实体名称和接口)。

public string EntityClassOpening(EntityType entity)

    var stringsToMatch = new Dictionary<string,string>   "Answer", "IJourneyAnswer" ,  "Fee", "ILegalFee"  ;
    return string.Format(
        CultureInfo.InvariantCulture,
        "0 1partial class 234",
        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);

正常人不应该这样对自己,圣经已经证明,一个人会为此下地狱。

【讨论】:

【参考方案5】:

我不确定如何执行您的要求,但有一种解决方法。通过覆盖自定义 DataAnnotationsModelValidatorProvider 的 GetValidators 进行动态数据验证。在其中,您可以阅读验证每个字段的规则(来自数据库、配置文件等)并根据需要添加验证器。它具有附加值,即您的验证不再与模型紧密耦合,并且无需重新启动站点即可更改。当然,这对你的情况来说可能有点过头了,但对我们来说却是理想的选择!

【讨论】:

我们在第一次实现这个结构时就这样做了。我们已经切换到 NHibernate,但这与解决方案无关。我们的验证代码按原样工作,没有任何更改(仅更改了数据访问层)。【参考方案6】:

修改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;

通过保存模型来重建你的类,你所有的方法都应该被注释。

【讨论】:

以上是关于给实体框架生成的类添加数据注解的主要内容,如果未能解决你的问题,请参考以下文章

如何在设计数据库模型中添加实体框架地理位置属性

Spring框架 之@Valid注解的使用(嵌套类型的效验)

为 CoreData 生成的类添加前缀

将“额外数据”添加到 LINQ to SQL 生成的实体?

Eclipse 通过JPA自动生成注解实体

如何用注解简化SSH框架