When writing validation attributes, you can use ValidationContext to get some validation information, such as the name of the property you are checking, the type of object you are checking, etc.
Thus, you do not need to declare which property you want to check for uniqueness or which object you should check, or an event that you do not need to retrieve using reflection, because the value is passed to the IsValid method.
When using DbContext, you can execute Sql queries so that you can verify uniqueness using an SQL query. This is easier than trying to create a generic linq query on the fly.
Maybe this idea will help you. Here are some changes to your code in line with the idea:
protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var db = new YourDBContext(); var className = validationContext.ObjectType.Name.Split('.').Last(); var propertyName = validationContext.MemberName; var parameterName = string.Format("@{0}", propertyName); var result = db.Database.SqlQuery<int>( string.Format("SELECT COUNT(*) FROM {0} WHERE {1}={2}", className, propertyName, parameterName), new System.Data.SqlClient.SqlParameter(parameterName, value)); if (result.ToList()[0] > 0) { return new ValidationResult(string.Format("The '{0}' already exist", propertyName), new List<string>() { propertyName }); } return null; }
To use this attribute, simply put [IsUnique] over your property.
[IsUnique] YourProperty { get; set; }
Then run the test using this code:
var db = new YourDbContext(); db.Configuration.ValidateOnSaveEnabled = true; db.Categories.Add(new YourEntity() { YourProperty = "DuplicateName" }); db.SaveChanges();
Itโs good practice to check only that aspect of your object using attributes that can be checked offline.
Validation attributes such as StringLength, RegularExpression, Required, and such validations are examples of good attributes, and validation attributes that validate uniqness rules or other database related examples of inappropriate attributes.