2013-09-06 6 views
7

पर एक ऑब्जेक्ट पास करें, मैं ऑब्जेक्ट के अंदर संग्रह को सत्यापित करने के लिए FluentValidation का उपयोग कर रहा हूं, संग्रह ऑब्जेक्ट्स के तत्व को मूल ऑब्जेक्ट के तत्व से तुलना कर रहा हूं।ऑब्जेक्ट का एक तत्व FluentValidation SetValidator के कन्स्ट्रक्टर

लक्ष्य आउटपुट संग्रह में विफल होने के लिए संग्रह में प्रत्येक विफल आइटम के लिए प्रमाणीकरण विफलताओं को प्राप्त करना है।

मेरे पास सॉफ़्टवेयर आइटम की एक सूची है जिसमें सॉफ़्टवेयर आइटम हैं। यदि आदेश विरासत प्रणाली के लिए है, तो चयनित सॉफ़्टवेयर केवल विरासत सॉफ़्टवेयर हो सकता है, और इसके विपरीत, गैर-विरासत प्रणाली में केवल गैर-विरासत सॉफ़्टवेयर हो सकता है।

मेरे मॉडल:

public class SoftwareOrder 
{ 
    public bool IsLegacySystem; 
    public List<SoftwareItem> Software; 
    (...other fields...) 
} 
public class SoftwareItem 
{ 
    public bool Selected; 
    public bool IsLegacySoftware; 
    public int SoftwareId; 
} 

प्रमाणकों:

public class SoftwareOrderValidator : AbstractValidator<SoftwareOrder> 
{ 
    public SoftwareOrderValidator() 
    { 
    (..other rules..) 

    When(order => order.IsLegacySystem == true,() => 
    { 
     RuleForEach(order => order.SoftwareItem) 
      .SetValidator(new SoftwareItemValidator(true)); 
    }); 
    When(order => order.IsLegacySystem == false,() => 
    { 
     RuleForEach(order => order.SoftwareItem) 
      .SetValidator(new SoftwareItemValidator(false)); 
    }); 
    } 
} 
public class SoftwareItemValidator : AbstractValidator<SoftwareItem> 
{ 
    public SoftwareItemValidator(bool IsLegacySystem) 
    { 
    When(item => item.Selected,() => 
    { 
     RuleFor(item => item.IsLegacySoftware) 
      .Equal(IsLegacySystem).WithMessage("Software is incompatible with system"); 
    }); 
    } 
} 

आप देख सकते हैं, मैं जब प्रत्येक शर्त के लिए एक होने से इस को पूरा कर रहा हूँ। यह काम करता है, लेकिन यह DRY का उल्लंघन करता है और केवल दो स्थितियों से अधिक स्थिति में उपयोग करने के लिए व्यावहारिक नहीं है।

मैं आदर्श रूप में एक भी RuleForEach कि ऐसा कर सकता है करना चाहते हैं, कोई Whens, जरूरत कुछ की तरह:

RuleForEach(order => order.SoftwareItem) 
    .SetValidator(new SoftwareItemValidator(order => order.IsLegacySystem)); 

लेकिन मुझे लगता है कि निर्माता में IsLegacySystem पारित करने के लिए किसी भी तरह से नहीं देख सकता।

उत्तर

14

मैं देख कितने दृश्य इस अनुत्तरित सवाल हो गया था के बाद यह एक और शॉट, 2 साल बाद, देने का फैसला किया। मैं दो उत्तरों के साथ आया हूँ।

पहला जवाब प्रश्न में वर्णित स्थिति का सबसे अच्छा समाधान है।

public class SoftwareOrderValidator : AbstractValidator<SoftwareOrder> 
{ 
    public SoftwareOrderValidator() 
    { 
     RuleForEach(order => order.SoftwareItem) 
     .Must(BeCompatibleWithSystem) 
     .WithMessage("Software is incompatible with system"); 

    } 

    private bool BeCompatibleWithSystem(SoftwareOrder order, SoftwareItem item) 
    { 
     if (item.Selected) 
     return (order.IsLegacySystem == item.IsLegacySoftware); 
     else 
     return true; 
    } 
} 

विधेय प्रमाणकों (a.k.a चाहिए) दोनों तर्कों के रूप & संपत्ति आपत्ति ले सकते हैं। यह आपको IsLegacySystem, या मूल ऑब्जेक्ट की किसी भी अन्य संपत्ति के विरुद्ध सीधे तुलना करने की अनुमति देता है।

आपको शायद इस दूसरे उत्तर का उपयोग नहीं करना चाहिए। अगर आपको लगता है कि आपको एक सार वैलिडेटर के कन्स्ट्रक्टर में तर्क पारित करने की आवश्यकता है, तो मैं आपको एक अलग दृष्टिकोण का पुनर्मूल्यांकन और खोजने के लिए प्रोत्साहित करता हूं। उस चेतावनी के साथ, इसे पूरा करने का एक तरीका यहां है।

असल में, एक डमी आवश्यक() का उपयोग करें ताकि आप कन्स्ट्रक्टर के बाहर, लैम्ब्डा के बाहर एक चर सेट कर सकें। फिर आप उस वैल्यू को दूसरे वैधकर्ता के निर्माता में प्राप्त करने के लिए उपयोग कर सकते हैं।

public class SoftwareOrderValidator : AbstractValidator<SoftwareOrder> 
{ 
    private bool _isLegacySystem; 

    public SoftwareOrderValidator() 
    { 
     RuleFor(order => order.IsLegacySystem) 
     .Must(SetUpSoftwareItemValidatorConstructorArg); 

     RuleForEach(order => order.SoftwareItem) 
     .SetValidator(new SoftwareItemValidator(_isLegacySystem)); 

    } 

    private bool SetUpSoftwareItemValidatorConstructorArg(bool isLegacySystem) 
    { 
     _isLegacySystem = isLegacySystem; 
     return true; 
    } 
} 
public class SoftwareItemValidator : AbstractValidator<SoftwareItem> 
{ 
    public SoftwareItemValidator(bool IsLegacySystem) 
    { 
    When(item => item.Selected,() => 
    { 
     RuleFor(item => item.IsLegacySoftware) 
      .Equal(IsLegacySystem).WithMessage("Software is incompatible with system"); 
    }); 
    } 
} 
+1

बहुत प्यारा मुश्किल – pirimoglu

1

इस दृष्टिकोण है जो कस्टम विधि का उपयोग करता के बारे में कैसे:

public class SoftwareOrder 
{ 
    public bool IsLegacySystem; 
    public List<SoftwareItem> Software; 
} 
public class SoftwareItem 
{ 
    public bool Selected; 
    public bool IsLegacySoftware; 
    public int SoftwareId; 
} 

public class SoftwareOrderValidator : AbstractValidator<SoftwareOrder> 
{ 
    public SoftwareOrderValidator() 
    { 
     Custom(order => 
     { 
      if (order.Software == null) 
       return null; 

      return order.Software.Any(item => order.IsLegacySystem != item.IsLegacySoftware) 
       ? new ValidationFailure("Software", "Software is incompatible with system") 
       : null; 
     }); 

     // Validations other than legacy check 
     RuleFor(order => order.Software).SetCollectionValidator(new SoftwareItemValidator()); 
    } 
} 

public class SoftwareItemValidator : AbstractValidator<SoftwareItem> 
{ 
    // Validation rules other than legacy check 
    public SoftwareItemValidator() 
    { 
    } 
} 
+0

यह व्यक्तिगत वस्तुओं को मान्य नहीं करता है, केवल संपूर्ण संग्रह को ही मान्य करता है। मैंने यह स्पष्ट करने के लिए अपना प्रश्न अपडेट किया है कि संग्रह में प्रत्येक विफल आइटम के लिए सत्यापन विफलता प्राप्त करना आवश्यक है। – friggle

+0

मैं इस जवाब को किसी भी तरह से 2 साल तक खोने के लिए क्षमा चाहता हूं। अगर यह कोई सांत्वना है, तो मुझे कभी समाधान नहीं मिला। – friggle

5

मैं जानता हूँ कि यह एक पुराने सवाल है और एक जवाब पहले से ही दिया गया है, लेकिन मैं आज इस सवाल पर ठोकर खाई और पता चला कि FluentValidation के वर्तमान संस्करण (मैं 6.2.1.0 उपयोग कर रहा हूँ) एक नया है SetValidator के लिए अधिभार जो आपको एक पैरामीटर के रूप में एक Func पास करने की अनुमति देता है।

तो, आप कर सकते हैं:

RuleForEach(x => x.CollectionProperty) 
    // x below will referente the Parent class 
    .SetValidator(x => new CollectionItemValidator(x.ParentProperty); 

उम्मीद है कि इस में किसी को वहाँ बाहर कर सकते हैं।

+0

प्रश्न के बावजूद इस उत्तर को पोस्ट करने के लिए धन्यवाद। यह वास्तव में मेरी मदद की! – Mir

संबंधित मुद्दे