We're throwing together a quick project (CRUD forms) and decided to skip view models and use EF entities directly in controllers and views. Since I'm not used to this approach, I'm confused about handling validation.
For example: a DB field has a length of 25. How does that get transferred (if it can) to a validation constraint in my view? If i was using an intermediate model, I would attach attributes to the model properties and it would work. How would I do this using EF objects directly? Thanks.
This can be done using MetadataType attribute on the Ef generated classes. The EF generates partial classes. So those can be extended and attribute added to it. Then another "buddy class" can be written that can have member decoration. For example
[MetadataType(typeof(EFGeneratedClass_MetaData))]
public partial class EFGeneratedClass
{
}
public partial class EFGeneratedClass_MetaData
{
[Required]
[Display(Name="Member1 Display")]
public string Member1 {get; set;}
}
Easiest thing to do is to use the DataAnnotations attributes that are in the System.ComponentModel.DataAnnotations anmespace.
MVC respects those and will populate your ModelError collection if any fail. In the case of your example, you could add a using statement for that namespace and then just flag a property with
[StringLength(25)]
and call it a day.
You need to use a partial 'buddy' meta class and decorate it with validation attributes.
For example, say your entity was 'Foo':
[MetadataType(typeof(FooMetadata))]
public partial class Foo {}
public class FooMetadata
{
//apply validation attributes to properties
[Required]
[Range(0, 25)]
[DisplayName("Some Neato Property")]
public int SomeProperty { get; set; }
}
For more information see this link on MSDN:
Customize Data Field Validation in the Model
Cheers.
Related
I have a form, where some fields are mandatory. A few of the mandatory fields have not always been mandatory, hence there are null values in the database.
If I add [Required] for the property, I will get a SqlNullValueException, because there are null values in the database.
What is the best practice to get a field to behave as if it had a [Required] attribute?
[Required]
public string? foo { get; set; }
You're a bit light on context here, but I assume you are using Entity Framework and you have a class setup for the entity and this is what has your [required] field. I am then assuming you are using this same class with your form.
If this is the case then, I would advise you to create a second class which will act as your view model. This way you have a data model (entity class) and a view model (front end specific class). Then you can easily separate the logic of the two behaviours.
You can use something like AutoMapper to make transferring of property values between the two a little easier too.
In my application I am creating my EDMX file using Database First Method.
I get classes generated for all of tables there.
I am able to use annotations like Required,Display,StringLength,RegularExpression,etc. there.
I know in my model of MVC I can use annotation named "Remote" by which I can validate my entity property.
Is there any way to use this "Remote" attribute in entity classes ? or may some other way to create custom annotation?
Update:
I have ViewModel Like this
public Exam Exam { get; set; }
public TestInfo Test { get; set; }
Both Exam & TestInfo are entity classes generated by entity framework.
There is property "ExamName" in entity class "Exam" which I want to validate for duplicate names.
Remote is a data annotation used to validate an input user enters in UI. It makes an ajax call to one of your action method (which you can specify) and expects a result value which tells whether this data already exists in your system.
You probably need to create a new view model for your view, instead of using the entity class created by entity framework, for your view. then you can have Remote attribute on that. In your action method ,you may deal with the actual entities to check the existence of the data.
public class RegisterVM
{
[Required]
[Remote("IsAvailable", "Validation")]
public override string UserName { get; set; }
}
Now you may have your IsAvailable action method to check the UserName exists or not. Also make sure now your Register viw is strongly typed to this new RegisterVM viewmodel.
#model RegisterVM
#using(Html.Beginform())
{
// your form controls
}
It does not makes sense to have Remote attribute on an Entity class. It should be on a view model.Otherwise you are mixing things up!
I am working on a project utilizing MVC4 and EF Data First in VS2012. The table has a primary key which does not have "id" in the field name so EF does not understand it should use it as the primary key. After EF generates the code I add the following annotations and using statements.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public partial class Game
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int GameNumber { get; set; }
If I base my models from the generate code the custom changes I make will be discard if I update the database models. How can I keep my custom changes and update the database EF data model.
Thanks
use MetadataTypeAttribute (MSDN) to define a metadata class on a partial implementation of your entity class, then decorate the properties in that metadata class.
Note that the decorated partial class implementation should exist in a file other than the autogenerated file so as to persist refreshing from DB.
(question: if your model is DB first, why doesn't it know what the PK is for the Game table? Whether or not the property has Id at the end doesn't matter when it's reading the table schema to generate the model...)
[MetadataType("GameMetadata")]
public partial class Game
{
public class GameMetadata
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int GameNumber;
}
}
I am curious as to why data validation is done using buddy classes. Consider the following example, where MyEntity is a Linq-to-SQL or Linq-to-Entities entity, and the class below is a partial class enhancing the entity.
[MetadataType(typeof(MyEntity.MyEntityMetadata))]
public partial class MyEntity
{
private class MyEntityMetadata
{
[Required(ErrorMessage = "The title is required.")]
public string Title { get; set; }
}
}
Why is the design so? When they designed DataAnnotations, why was this "buddy pattern" selected? Why not place the attributes directly in the entity?
I assume this prevents generated entities from overwriting custom Meta Data information.
The reason is practical - in linq-to-sql and linq-to-entities, the code representing the classes regenerated every time the object model is updated. In order for the annotations not to be overwritten when this happens, they need to be in a separate "buddy" class.
If you're using Data Annotations in a different context - say for a view model - then they can go on the original class itself.
I'm using a generated class as a model, and I wish to add DataAnnotation attributes to some of its properties. As it's a generated code, I don't want to add the annotations directly. Is there another way to attach them to a property?
I'd considered making the model an interface, and using a partial class to get the generated class to subscribe to it. Is there a less elaborate solution, assuming that would even work?
Yes there is. You have to create metadata class that will have the same properties that your original model, and connect it to your model with MetadataType attribute:
[MetadataType(typeof(MyModelMetadata))]
public partial class OriginalMyModel
{
}
public class MyModelMetadata
{
[Required]
public string MyProperty;
// ...
}
In the example ebove OriginalModel is your proper model class, and MyModelMetadata is a class used only for annotating properties. MyModelMetadata should have the same properties that your model has.
You can use the MetadataType attribute on your class:
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.metadatatypeattribute.aspx
In practice, I've seen the metadata get out of sync with a generated model pretty frequently, though, which can lead to some headaches. You may want to look into an alternate validation mechanism instead of data annotations.
I've been using Fluent Validation, which is very easy to pick up and start using. There is even a Fluent Validation to xVal integration piece in Fluent Validation 2.0 (still in beta) that you can bring into your project for client-side validation.
Fluent Validation allows you to define your validation in a separate class. All you would need to do is add an attribute to your generated class telling it what validator to use, which could be accomplished through partial classes.
Alternatively, you could create view-specific models that are mapped to from your domain model that contain your data annotations. In that case, simplify the back-and-forth mapping using something like AutoMapper. Then, if your domain model changes, you get compile-time errors versus the metadata approach.