C # Unique property of custom validation - common classes

I am trying to do a custom check [IsUnique]. This check if the property value is unique and returns the correct message.

This is my code, but this is only work for the specified class, is it possible to make a method that receives the corresponding class by metadata?

public class ArticleMetaData { [Required(AllowEmptyStrings = false)] [IsUnique("Name")] public String Name{ get; set; } } 

And my user check:

 class IsUnique : ValidationAttribute { public IsUnique(string propertyNames) { this.PropertyNames = propertyNames; } public string PropertyNames { get; private set; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var myproperty = validationContext.ObjectType.GetProperty(PropertyNames); var value = propiedad.GetValue(validationContext.ObjectInstance, null); IEnumerable<String> properties; List<string> propertiesList = new List<string>(); propertiesList.Add(myproperty.Name); var dba = new myContext(); if (dba.Articles.Any(article => article.Name == (string)value)) { return new ValidationResult("The name already exist", propertiesList); } return null; } } 

the idea would be to simply use the [isUnique] annotation, and the method to take a class with annotation and look for the corresponding object.

+7
c # validation entity-framework data-annotations
source share
3 answers

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.

+4
source share

I think the best way is to let the database do its work.

Create a database constraint so that two articles have the same name (or whatever uniqueness you need). Then, when a user creates a new article or updates an existing one with an existing article name, the database throws an exception. Catch this exception and inform the user about the problem.

+1
source share

It would be nice if there were common attributes, but they were not supported. However, you can try using the Set method for DbContext , which takes an entity type as a parameter. To request a non-generic DbSet , you can use the System.Linq.Dynamic library (you can add it from NuGet). It allows you to query DbSet using string predicates. Here is an example:

 var existingEntityQuery = myContext.Set(validationContext.ObjectType) .Where("Name= @0", (string)value); var enumerator = existingEntityQuery.GetEnumerator(); if (enumerator.MoveNext()) { var entity = enumerator.Current; if (entity != null) { return new ValidationResult("The name already exist", propertiesList); } } 
0
source share

All Articles