2015-05-19 4 views
2

У меня есть класс MainEntity, и у него есть коллекция SubEntity. Ниже приводится текущая проверка:Проверка FluentValidation для дубликата объекта в подсетевой

public class MainEntityValidator : AbstractValidator<MainEntity> 
{ 
    public MainEntityValidator() 
    { 
     RuleFor(x => x.SubEntities).SetCollectionValidator(new SubEntityValidator()); 
    } 

    public class SubEntityValidator : AbstractValidator<SubEntity> 
    { 
     public SubEntityValidator() 
     { 
      RuleFor(x => x.Field1).NotNull(); 
      RuleFor(x => x.Field2).NotNull(); 
     } 
    } 
} 

Как я могу добавить правило проверки, так что только уникальные SubEntity объекты (на основе Field1 и Field2) должны быть в коллекции?

ответ

3

Если вам необходимо применить правило проверки для сбора имущества, но по-прежнему необходимо иметь доступ к основной модели и (или) всей коллекции, а не только пункт проверяемого, то RuleForEach метод ваш выбор:

var comparer = new SubEntityComparer(); 

RuleForEach(x => x.SubEntities) 
    .Must((model, submodel) => model.SubEntities.Count(xsub => comparer.Equals(xsub, submodel)) == 1) // one match that ReferenceEquals hit 
    .WithMessage("The item with values {0}, {1} has duplicates in collection of {2} items", 
     (model, submodel) => submodel.Field1, 
     (model, submodel) => submodel.Field2, 
     (model, submodel) => model.SubEntities.Count); // in validation message generation you can access to current item as well as to main model 

Если вы нужно только одно сообщение об ошибке для правила проверки, которую вы описали - вы можете применить простое правило предиката для сбора имущества SubEntites:

RuleFor(x => x.SubEntities) 
    .Must(coll => coll.Distinct(new SubEntityComparer()).Count() == coll.Count) 
    .WithMessage("One or more items in collection of {0} items are duplicates", 
     (model, coll) => coll.Count); // has access to collection and to main model 

в обоих случаях я использовал тот же компаратор равенство, но вы можете переопределить Equals, а также использовать перегрузки IEnumerable методов расширения с перегрузкой, которые исключают параметр EqualityComparer.

Кодекс EqualityComparer перечислены ниже:

public class SubEntityComparer : IEqualityComparer<SubEntity> 
{ 
    public bool Equals(SubEntity x, SubEntity y) 
    { 
     if (x == null^y == null) 
      return false; 

     if (ReferenceEquals(x, y)) 
      return true; 

     // your equality comparison logic goes here: 
     return x.Field1 == y.Field1 && 
       x.Field2 == y.Field2; 
    } 

    public int GetHashCode(SubEntity obj) 
    { 
     return obj.Field1.GetHashCode() + 37 * obj.Field2.GetHashCode(); 
    } 
} 

Update:

В обоих способах осуществления проверки для сбора вы можете использовать SetCollectionValidator(new SubEntityValidator()) для проверки каждого элемента с помощью простых правил самостоятельно.

+1

Вам не нужно утилизировать SubEntityComparer? – polonskyg

+0

IEqualityComparer реализация stateless (без полей), более того, он участвует в закрытии - метод проверки будет выполнен после завершения определения кода определения. –

+0

Почему вы решили реализовать компаратор, а не просто это: '.Must ((model, subodel) => model.SubEntities.Count (xsub => xsub.Field1 == submodel.Field1 && xsub.Field2 == subodel.Field2)) == 1) '? – Mir

0

Я полагаю, что ответ на ваш вопрос заключается в том, чтобы сравнить каждый элемент в вашей коллекции с каждым другим элементом и не проверить, когда объекты «равны». Хотя я бы не рекомендовал делать это, если ваша коллекция могла содержать более тривиального количества элементов. Лучшим подходом было бы реализовать Equals() и GetHashCode(), чтобы типы коллекций в библиотеке базового класса предсказуемо обрабатывали объекты SubEntity. Я бы опубликовал пример, но я не знаю, как выглядят ваши объекты, поскольку вы их не размещали. Во всяком случае, если вы реализуете эти методы значимым образом, вы можете определить свою коллекцию как тип, который уже имеет соответствующие уникальные ограничения (например, HashSet of T).

 Смежные вопросы

  • Нет связанных вопросов^_^