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.
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 implementing a project using mvc 4 and entity framework.
where i used data first approach. and i am implementing a partial class for my models for various business logic.
my question is how can i set validation rule on my properties. shown in below.
[Required]
public string FirstName { get; set; }
if i manually added this code "[Required]" on a property (entity framework generate models).
and then if i need to change model for database changes. then all my validation rule is gone
how can i over come this problem, without using code first approach.
As you've found out you should never edit the generated files since changes are lost when you regenerate them.
A better architecture than to use the entities as models for your views is to insert a separate View Model between the view and the entity. The view model should correspond closely to the needs of the view and often retrieves data from several underlying entities.
The attributes then goes on the view model properties instead of on the entities.
View models also remedies the risk of mass assignment vulnerabilities in your application, which are particularly dangerous if you are using lazy loading in your entities.
Another way around this (using CodeFirst) is to use a Fluent Validation. The CustomerValidator will always point at the regenerated Customer class (unless you change the Customer class name obviously)
using FluentValidation;
public class CustomerValidator : AbstractValidator<Customer> {
public CustomerValidator {
RuleFor(customer => customer.Surname).NotNull();
}
}
Scenario: I am writing a program that handles report generation.
I have the report stored in a database, mapped to an EF model. There are some non-database fields (i.e. some fields are auto-calculated based on other fields that ARE in the db). Would it make sense to have one class that solely maps to the DB, and another class that takes that information and additionally has the other calculating fields?
i.e. a sample class to interact with the codefirst database would be
public class Report{
public int CategoryOneSeverity {get; set;}
public int CategoryTwoSeverity {get;set;}
public string Title {get;set;}
}
Would it make sense to make another class, like:
public class ReportModel{
public int CategoryOneSeverity;
public int CategoryTwoSeverity;
public string Title;
public int RiskRating{
get{ return CategoryOneSeverity + CategoryTwoSeverity; }
}
}
Or should the RiskRating property be in the EF model.
Yes, I absolutely believe you should have different classes to model your domain than your DB. Unless your application is extremely trivial, if you try to map your domain objects directly, you invariably have to change them to match what you need your data structure to be, and possibly expose things you don't want to expose. Think of it as a violation of the Single Responsibility principle; your class has two reasons to change if you make it your domain object and map it directly. One is in response to changing business requirements, the other is in response to changing data storage schema.
"Would it make sense to have one class that solely maps to the DB, and
another class that takes that information and additionally has the
other calculating fields?"
Most likely yes. Usually I would create a new class suffixed with "ViewModel" such as HumanResourcesReportViewModel if my entity class was HumanResourcesReport.
There's lots of variations on how to use ViewModels, and we could get into a pedantic debate about terminology, but conceptually, take your entity and create a new class with that data plus whatever additional information you need to process the report. In this case the report generation is in a way the View of the MVC model, so I don't think it's offensive to call the class holding the data a ViewModel.
Are you using Code First or DB First?
You can have auto calculated fields in your model, which are not mapped to fields in the database.
It also depends on your architecture. If you're using DB first, refreshing your EF model would update your EF classes, losing your mapped fields. In the DB-First scenario, an alternative would be to use the EF model class as your base class and inherit from it for your report class.
public class ReportModel
{
public int CategoryOneSeverity;
public int CategoryTwoSeverity;
public string Title;
}
public class ReportClass : ReportModel
{
public int RiskRating
{
get { return CategoryOneSeverity + CategoryTwoSeverity; }
}
}
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.