可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following class generated by entity framework:
public partial class ItemRequest
{
public int RequestId { get; set; }
//...
I would like to make this a required field
[Required]
public int RequestId { get;set; }
However, because this is generated code this will get wiped out. I can't imagine a way to create a partial class because the property is defined by the generated partial class. How can I define the constraint in a safe way?
回答1:
The generated class ItemRequest
will always be a partial
class. This allows you to write a second partial class which is marked with the necessary data annotations. In your case the partial class ItemRequest
would look like this:
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;}
//...
}
}
回答2:
As MUG4N answered you can use partial classes but will be better use interfaces instead. In this case you will have compilation errors if EF model doesn't correspond to validation model. So you can modify your EF models without fear that validation rules are outdated.
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 */
}
}
P.S. If you are using project type which is differ from ASP.NET MVC (when you perform manual data validation) don't forget to register your validators
/* Global.asax or similar */
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));
回答3:
I found a solution like MUG4N's answer, but instead, nesting the MetaData
class within the entity class, thereby reducing the number of classes in your public namespace list, and eliminating the need to have a unique name for each metadata class.
using System.ComponentModel.DataAnnotations;
namespace MvcApplication1.Models
{
[MetadataType(typeof(MetaData))]
public partial class ItemRequest
{
public class MetaData
{
[Required]
public int RequestId;
//...
}
}
}
回答4:
This is sort of extension to @dimonser answer if you regenerate your db model you will have to manually re-add interfaces on those classes.
If you have stomach for it you can also modify your .tt
templates:
Here's example of auto-generating interfaces on some classes, this is fragment from .tt
just replace EntityClassOpening
method in yours with following (and obviously var stringsToMatch
with your entity names and interfaces).
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);
}
No normal person should do this to himself though, it has been proven in Bible that one goes to Hell for this.
回答5:
I am not sure how to do what you are asking for but there is a way around it. Dynamic data validation by overriding the GetValidators of your custom DataAnnotationsModelValidatorProvider. In it you can read the rules for validating each field (from a database, config file, etc.) and add validators as need be. It has the added values that your validation is no longer tightly coupled to the model and can be changed without need to even restart the site. Of course it might be overkill for your case, but it was ideal for ours!
回答6:
Modify the T4 template adding required annotations, this file is usually named MODELNAME.tt
find where the T4 is creating the class and methods to know where to put these.
<#=codeStringGenerator.IgnoreJson(navigationProperty)#>
//create this method in file
public string IgnoreJson(NavigationProperty navigationProperty){
string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore]
[IgnoreDataMember]";
return result;
}
You will also need to add the namespaces;
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;
Rebuild your classes by saving your model, all your methods should be annotated.