2015-08-23 25 views
7

Próbuję utworzyć niestandardową weryfikację [IsUnique]. To sprawdzenie, czy wartość właściwości jest unikalna i zwraca właściwy komunikat.Niestandardowa własność walidacji niestandardowej - ogólne klasy

To jest mój kod, ale to tylko praca dla określonej klasy, jest możliwe, aby zrobić metodę, która otrzyma właściwą klasę przez metadane?

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

A mój zwyczaj sprawdzania poprawności:

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; 
     } 
    } 

pomysł byłoby po prostu użyć adnotacji [isUnique] oraz metoda podjąć klasy z adnotacją i szukać odpowiedniego podmiotu.

+1

możliwe duplikat [Mogę zapisać rodzajowych atrybut w polu obiektu w] (http://stackoverflow.com/questions/304640/can-i-store-the-generics-attribute -into-obiektu-pola) –

+0

Czy próbujesz uniemożliwić użytkownikowi zapisywanie duplikatów rekordów w bazie danych? –

+0

@ JuanM.Elosegui to jest mój cel. nie duplikuj nazw, wiadomości e-mail itp. byłby to unikalny klucz SQL – grteibo

Odpowiedz

4

Podczas pisania atrybutów sprawdzania poprawności można użyć obiektu sprawdzania poprawności, aby uzyskać informacje o sprawdzaniu poprawności, takie jak sprawdzana nazwa usługi, typ sprawdzanego obiektu i tak dalej.

Nie musisz zadeklarować, która właściwość ma zostać sprawdzona pod kątem unikalności lub która jednostka powinna zostać sprawdzona, lub jeśli nie musisz odzyskiwać wartości za pomocą refleksji, ponieważ wartość została przekazana do metody IsValid .

Podczas korzystania z DbContext, możesz wymieniać zapytania SQL, abyś mógł sprawdzić unikalność za pomocą zapytania sql. Jest to prostsze niż spróbuj utworzyć ogólne zapytanie linq na bieżąco.

Być może ten pomysł ci pomoże. Oto kilka zmian w kodzie zgodnie z ideą:

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; 
} 

Aby korzystać z tego atrybutu, wystarczy umieścić [IsUnique] powyżej nieruchomości.

[IsUnique] 
YourProperty { get; set; } 

Następnie uruchom test za pomocą takiego kodu:

var db = new YourDbContext(); 
db.Configuration.ValidateOnSaveEnabled = true; 
db.Categories.Add(new YourEntity() { YourProperty = "DuplicateName" }); 
db.SaveChanges(); 

Jest to dobra praktyka, aby potwierdzić tylko taki aspekt swojego podmiotu przy użyciu atrybutów, które mogą być weryfikowane w trybie offline.

Atrybuty walidacji takie jak StringLength, RegularExpression, Required i takie walidacje to przykłady dobrych atrybutów i Atrybuty walidacji, które sprawdzają unikalność lub inne reguły związane z bazą danych są przykładami nieodpowiednich atrybutów.

+0

Próbuję zastosować twój przykład. O twoim ostatnim paragrafie zgadzam się z tym, ale w niektórych przypadkach system musi potwierdzić, że użytkownik nie robi duplikatów nazw. Dzięki za porady! – grteibo

+0

@grteibo, serdecznie zapraszamy :) W przypadkach, w których system musi zapobiegać duplikacji danych, lepiej jest to zrobić w kodach Business Logic. Tam możesz utworzyć ogólną metodę sprawdzania duplikatów i ponownego użycia. Składnia takiej metody może być: bool IsUnique (nazwa właściwości łańcucha, wartość obiektu, YourDbContext db) –

+0

początkowo podszedłem do walidacji wykonań w systemie logiki biznesowej. Ale myślałem, że najlepiej będzie zrobić to za pomocą adnotacji w bytach. – grteibo

1

Myślę, że najlepszym sposobem jest pozwolić bazy danych zrobić swoje prace.

Utwórz wiązanie w bazie danych, aby zapobiec sytuacji, w której dwa artykuły mają taką samą nazwę (lub dowolną wyjątkowość). Następnie, gdy użytkownik utworzy nowy artykuł lub zaktualizuje istniejący o istniejącą nazwę artykułu, baza danych rzuci wyjątek. Złap ten wyjątek i poinformuj użytkownika o problemie.

0

Byłoby miło, gdyby były ogólne atrybuty, ale takie nie są obsługiwane. Można jednak spróbować użyć metody Set dla obiektu DbContext, która pobiera typ jednostki jako parametr. Aby wysłać zapytanie do nietypowego DbSet, możesz użyć biblioteki System.Linq.Dynamic (możesz ją dodać z NuGet). Pozwala na zapytanie do DbSet przy użyciu predykatów łańcuchowych.Oto przykład:

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); 
    } 
}