Question

DbSet<T>.Local provides an ObservableCollection that you can bind to WPF controls. In my case, I'm binding it to a grid.

If I was using view models, I would have them implement INotifyDataErrorInfo or IDataErrorInfo, and then write Fluent Validation validators to handle validation.

But here I'm binding to the models via DbSet<T>.Local. How should I handle validation?

Should I implement INotifyDataErrorInfo or IDataErrorInfo on my models?

Or is there some alternative?

Was it helpful?

Solution

If you are application is a thick client, meaning all layers of the application are on a single physical machine, then you should implement IDataErrorInfo on your models.

On the other hand, if your application is a thin multi-tired application, meaning that your model is implemented on a server and you are using the WPF desktop application to communicate with the server side code then you should implement INotifyDataErrorInfo.

OTHER TIPS

Yes I think implement implementing IValidatableObject in POCO Models makes sense. And you have probably noticed public ObservableCollection<TEntity> Local { get; }

There are several ways to do this. So a some homework.

As some background , might be useful

Then check this out

So we know EF has the concept of triggering Validations.

Configuration.ValidateOnSaveEnabled = true; 

EF will also call IEnumerable<ValidationResult> ValidateInstance();

from interface IValidatableObject

if your entity POCO implements IValidatableObject

EF will trigger validate on SAve. You can also easily trigger validations when you need to.

This all neatly links in with UoW concept.

 public IEnumerable<DbEntityValidationResult> GetDbValidationErrors() { return 
        Context.GetValidationErrors(); }   // Standard Context call get the problems

which can be used catch (Exception ex) {.... var x = GetDbValidationErrors(); //....

So i think you are on the right track...

EDIT: Add SAMPLE POCOBase and demonstrate trigger validation.

public interface IFBaseObject : IValidatableObject {
    // a POCO object must implement the VALIDATE method from    IValidatableObject
    bool IsValidInstance();
    IEnumerable<ValidationResult> ValidateInstance();

}

public abstract class BaseObject : IFBaseObject {

     // .... base object stuff removed....

    /// <summary>
    /// Get called every a Validation is trigger on an object.  Here we return and Empty resultset to start with.
    /// If you override ALWAYS call Base first and Continue to add your own results as desired.
    /// Never fail to call base First !
    /// </summary>
    public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
        # region Sample implementation for a POCO thats needs validation

        /* Sample Implementation a sub type POCO might use.
         var validationResult = base.Validate(validationContext).ToList();  

         if (true) // the condition that leads to a validation error
         {
             var memberList = new List<string> { "PropertyName" }; // the name of the offending property
             var error = new ValidationResult("Error text goes here", memberList); // use teh textpool !!! no hardcoded texts
             validationResult.Add(error);
         }

         return validationResult;
       */

        # endregion

        // now back in the base Class.
        var validationResult = new List<ValidationResult>();
        // hand back a list that is empty so errors if any can be added by SUBclasses
        // we can check any Poco that implements a certain interface centrally.  
        var thisIsKeyGuid = this as IFKeyGuid;
        if (thisIsKeyGuid != null) {
            if (thisIsKeyGuid.Id == Guid.Empty) {
                validationResult.Add(new ValidationResult("Id is required", new List<string>() {"Id"}));
            }
        }

        return validationResult;
    }

    /// <summary>
    /// Allows explicit triggering of Validation and returns a TRUE or false answer. Call anytime
    /// </summary>
    /// <returns></returns>
    public virtual bool IsValidInstance() {
        List<ValidationResult> vResults;
        return SelfValidation(out vResults);
    }

    /// <summary>
    /// Calls Self Validation which uses THIS object as the context for validation.
    /// This means you can trigger a validation without first declaring a validation context.
    /// IValidatableObject is effectively called for you. Witch causes "Validate" to be called
    /// </summary>
    /// <returns></returns>
    public IEnumerable<ValidationResult> ValidateInstance() {
        List<ValidationResult> vResults;
        SelfValidation(out vResults);
        return vResults;
    }

    /// <summary>
    /// Although SelfValidation is defined at BaseObject level, this triggers the VALIDATION process on the current Object
    /// see http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator.aspx for mroe details
    /// So if a POCO Object has overridden  public virtual IEnumerable of ValidationResult Validate(ValidationContext validationContext) 
    /// then this method will be called.  It should of course call :base.Validate
    /// </summary>
    /// <returns>true or false</returns>
    private bool SelfValidation(out List<ValidationResult> vResults) {
        var vc = new ValidationContext(this, null, null);
        vResults = new List<ValidationResult>();
        var isValid = Validator.TryValidateObject(this, vc, vResults, true);
        return isValid;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top