MVC 4 Manual validation with Data Annotation - entity-framework

I admit I found many similar question but not exactly this :)
I have entities with data annotation attributes:
public class BaseEntity
{
[Required, DataType(DataType.DateTime)]
public DateTime CreatedAt { get; set; }
public string CreatedBy { get; set; }
}
public class ExchangeRights : BaseEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required, DataType(DataType.EmailAddress)]
public string Email { get; set; }
}
And I try to validate an empty object:
ExchangeRights r = new ExchangeRights();
ValidationContext vCtx = new ValidationContext(r);
List<ValidationResult> res = new List<ValidationResult>();
Validator.TryValidateObject(r, vCtx, res, true);
It's only result one Error. That the Email field is required. But not indicate that there is not email format and not indicate that the CreatedAt field is not set (ok maybe it's because non nullable value type)
But here is the twist.
First I really want that every error should be indicated it's empty, it's not email format.
But the bigger problem is that if I set the Email to "asd" the method return no error.
However it's wierd if I use this Entity with strongly typed view (using MVC4 with Razor) on a create page all works fine.
The form indicate that the Email is requires or if I set than it says not valid email address format.
Also indicates that the CreatedAt field is required (with or without the Required attribute!!) and if I set it it says not valid datetime format.
Any help/idea/hunch would be appreciated.
Thanks,
Péter

for the validation of the email you should use the EmailAddress validation attribute. [EmailAddress].
For the CreatedAt, as DateTime is a non nullable type, when you create a ExchangeRights instance, the property CreatedAt is populated with DateTime.MinValue. So the property has a value. If you want a differente behavior, use DateTime? instead of DateTime.
Hope this helps.

You can use the DataTypeAttribute attribute for the following reasons: to provide additional type information for a data field, to associate a custom field template with a data field. DataTypeAttribute doesn't used for validation it's can be used for provide some additional metadata information. To validate email you can use DataAnnotations Extensions EmailAttribute or write you own validation attribute.
You can find more information in
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.datatypeattribute.aspx

Related

ServiceStack AutoQuery - Check for null in nullable DateTime-field

I user ServiceStack autoquery to load information. I have a class like this one:
public class QueryItem: QueryDb<Item>
{
public string Name { get; set; }
public DateTime? BirthdayNotEqualTo { get; set; }
}
As written in the documentation, I should be able to receive all items that are not null in the Birthday column like this:
QueryResponse<Item> item = jsonServiceClient.Get(new QueryItem {
BirthdayNotEqualTo = null
});
However, I receive all items, regardless of the null-filter above. How can I change that? The values in the database are correctly set to null.
It's not possible to send a null value using the ServiceClient. A null value, like default(DateTime?) means no value, so there's no "null filter" sent and your query is the same and indistinguishable from sending an Empty QueryItem DTO.
You'd need to use a Custom AutoQuery Implementation or a Customizable Query like:
[QueryDbField(Template = "{Field} IS NOT NULL", Field = "Birthday")]
public bool? BirthdayIsNotNull { get; set; }

Required Properties on optional Entity Framework Complex Types

I want to define [Required] attributes on a Complex Type in Entity Framework. For example, I have a Customer entity with an optional Address. The Address entity has a required PostCode property.
[ComplexType]
public class Address {
public string Address1 { get; set; }
[Required]
public string PostCode { get; set; }
}
public class Customer {
public int CustomerId {get;set;}
public Address Address {get;set;}
}
I do NOT want to store my Complex type as a separate entity (I'm not actually using Address, this just an easy illustration of the problem). I cannot leave Customer.Address null, because this gives the error:
Null value for non-nullable member. Member: 'Address'.
If I supply an empty Address entity, the validation fails on the PostCode field because of the Required attribute.
Is there any way to achieve this? I'm using EF5/NET4.5.
It's not possible with a complex type. You'll need to create an Address entity if you want it to be nullable.
What EF will do with a complex type is map the properties to the same table - which it sounds like you've intended.
Because of that - your schema for your example would look like this:
With a non-nullable column for Address_PostCode, since it's not valid in the database there's not a way for EF to create the row, without your object having an address, and a postcode.

Customizing the entity in the entity framework

I have the following problem: I have a table in the database called Person which have all the relevant data such as first name, last name, date of birth, sex etc ... . My question is : Is it possible to hide some of the attributes and if yes how can i achieve that. I need that because in my entity instead of date of birth I want an attribute called age which will take the date of birth and calculate the age. Also I want to hide another column called job which has default value N for no and also can be Y for yes. Instead of it I want to have the same column but with true or false. I know that I can achieve that changing the database but in my case I am not allowed to do that. And the last point: is there away to add additional columns which doesn't have a representation in the database ..for example a computed one which takes the attribute salary and based on it (for example if it is more or less than 500 euros) calculates the bonuses ? Thanks :)
Place your context and entities into a seperate project. The Person entity you've described could be done as follows:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
internal DateTime DateOfBirth { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public double AgeInYears { get { return DateTime.Now.Subtract(this.DateOfBirth).TotalDays / 365; } }
public char Sex { get; set; }
internal string Job { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public bool HasJob { get { return this.Job == "Y"; } }
}
Doing the above will only expose FirstName, LastName, AgeInYears, Sex, and HasJob to other projects, in the datatype you want.
To add a column that doesn't exist in the database, just use the appropriate Data Annotation as shown above.
To hide a column, mark it as internal.
Hope that helps.

Dynamic validation on MVC 2

This works fine
[MetadataType(typeof(Area_Validation))]
public partial class Area
{
...
}
public class Area_Validation
{
[Required(ErrorMessage = "Please add this field.")]
public int Email { get; set; }
[Required(ErrorMessage = "Please add this field")]
public string Name { get; set; }
}
but how about if Area_Validation is dynamically created? for example Subscription Fields that on back-end can be created by the user and end up like this:
How can I set the Metadata on each field for auto validation?
Currently I'm doing:
public class SubscriberFormViewModel
{
public List<SubscriberFieldModel> Fields { get; private set; }
public Calendar Calendar { get; private set; }
public Company Company { get; private set; }
public SubscriberFormViewModel()
{
// TODO: This is only for testing while validation is not set
}
public SubscriberFormViewModel(Decimal calendarId)
{
if (calendarId > 0)
{
SubscribersRepository db = new SubscribersRepository();
Calendar calendar = db.GetCalendarById(calendarId);
Company company = db.GetCompanyById(calendar.company_id);
this.Fields = db.FindAllSubscriberFieldsByCalendar(calendarId);
this.Calendar = calendar;
this.Company = company;
}
else
this.Fields = new List<SubscriberFieldModel>();
}
}
and I want to set the Metadata in all Fields property
In other words, this Fields are filled up from the Database and can have several types, can be a string, number, dropdown, etc ... kinda like MailChimp Fields Properties:
is there a way to do this programmaticaly or I need to create a jQuery plugin to validate it and stop using use validation from MVC2 ?
Thank you
Actually you can make several validation scenarios, one per type(or more per type if you need). Then Add this validation rules on type creation. When you need to validate, you can call template Validate method, that will check if these rules and if not - will add errors to ModelState, that you will be able to show on front end.
Actually its not that profitable to add any attributes, as attributes pro is that you can decorate your type with them. When you are doing some dynamic things, you`d better have some dynamic way to add validation.
I dont think you can do this using Data Annotations attributes.
There is a project in Codeplex, called Fluent Validation that permit you to add validation rules in a fluent way using .Net code. I never used that project but it seems that maybe can help you in your case with dynamically created objects.
Hope it helps!

Entity Framework error when submitting empty fields

VS 2010 Beta 2, .NET 4.
In my ASP.NET MVC 2 application, when I submit a form to an action method that accepts an object created by the entity framework, I get the following error:
Exception Details: System.Data.ConstraintException: This property cannot be set to a
null value.
Source Error:
Line 4500: OnTextChanging(value);
Line 4501: ReportPropertyChanging("Text");
Line 4502: _Text = StructuralObject.SetValidValue(value, false);
Line 4503: ReportPropertyChanged("Text");
Line 4504: OnTextChanged();
The property is called "Text" and is of type "text NOT NULL" in MS SQL 2008.
My action will check if the value is nullorempty, if it is, a model error will be added, but I get the error as soon as I submit the form.
Are you binding directly to the entity? Sure looks like it. So you have two choices:
Write a custom model binder which translates null -> empty string.
Bind to an edit model which allows nulls instead, and then change this to empty string when you copy the values to the entity in the action.
I'd choose #2, personally. I think you should always use view/edit models, and this is a great example of why.
I was having the same problem. I looked around and found a work around here. It describes the problem as being caused by the EF validation taking place before the Required field validation. It also shows how we can work around this problem by using a [DisplayFormat] Tag. Hope this will help you.
Here's the link to the question and the workaround:
Server-side validation of a REQUIRED String Property in MVC2 Entity Framework 4 does not work
Is this an issue with the MVC2 and Entity Framework 4 or is this by design? It appears that validation of EF properties works fine for datetime non-nullable (required) fields and data type validation of numeric versus string fields is working without having to use ViewModels.
I recreated the issue using with a simple FOOBAR table using a single, non-nullable varchar(50) column called barName in slq 2008. I generated the EF model from that database and quickly added a controller and a CREATE view for the FOOBAR entity. If I try to POST to the CREATE action without entering in a value for the property barName, VS steps into an exception within the designer.cs file of the model (just like the one above). When, I try to step past the exception, the validation message shows up on the form and the field is highlighted in pink.
It seems like something is not firing in the correct sequence. Because the exception occurs before VS steps into the HTTPPOST CREATE method.
I found the code from the ASP.Net MvcMusicStore sample helpful. http://mvcmusicstore.codeplex.com/releases/view/44445#DownloadId=119336
It appears that binding to the ViewModel fixes the issue.
namespace MvcMusicStore.ViewModels
{
public class StoreManagerViewModel
{
public Album Album { get; set; }
public List<Artist> Artists { get; set; }
public List<Genre> Genres { get; set; }
}
}
........
namespace MvcMusicStore.Models
{
[MetadataType(typeof(AlbumMetaData))]
public partial class Album
{
// Validation rules for the Album class
[Bind(Exclude = "AlbumId")]
public class AlbumMetaData
{
[ScaffoldColumn(false)]
public object AlbumId { get; set; }
[DisplayName("Genre")]
public object GenreId { get; set; }
[DisplayName("Artist")]
public object ArtistId { get; set; }
[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
public object Title { get; set; }
[DisplayName("Album Art URL")]
[StringLength(1024)]
public object AlbumArtUrl { get; set; }
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00, ErrorMessage="Price must be between 0.01 and 100.00")]
public object Price { get; set; }
}
}
}
Ashish Shakya's answer helped me. I added this attribute to the property and now it works.
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
So it looks like this:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Import the namespace:
using System.ComponentModel.DataAnnotations;
And add the attribute property [Required]
[Required]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Thus ModelState.IsValid equals false, showing error message in the validation and will not fail on the server with Null.
I had the same problem and fixed it by making false to true like this:
Line 4502:
_Text = StructuralObject.SetValidValue(value, false);
I just had the same problem myself, and came here to find the solution. However, the answer can be enhanced.
Svavar's and HackITMngr were on the right track, however combining both gives the best outcome. You don't want to go decorating the generated classes, as you risk losing your custom changes upon modifications to the EF model.
[MetadataType(typeof(MyTableMetaData))]
public partial class MyTable
{
// Validation rules for the Album class
public class MyTableMetaData
{
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public string MyTextProperty { get; set; }
}
}
To settle any arguments between the two. I'd say Svavar's was the direct answer, HackITMngr was the enhancement.
Works great for me!
I set StoreGeneratedPattern property as Computed for each field and it solved the problem for me.