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