This looks like a job for the Enterprise Library Validation Application Block (VAB). VAB has been designed to return all errors. Besides this, it doesn't thrown an exception, so you can simply ask it to validate the type for you.
When you decide to use the VAB, I advise you to -not- use the OnXXXChanging and OnValidate methods of LINQ to SQL. It's best to override the SubmitChange(ConflictMode) method on the DataContext class to call into VAB's validation API. This keeps your validation logic out of your business entities, which keeps your entities clean.
Look at the following example:
public partial class NorthwindDataContext
{
public ValidationResult[] Validate()
{
return invalidResults = (
from entity in this.GetChangedEntities()
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
from result in results
select result).ToArray();
}
public override void SubmitChanges(ConflictMode failureMode)
{
ValidationResult[] this.Validate();
if (invalidResults.Length > 0)
{
// You should define this exception type
throw new ValidationException(invalidResults);
}
base.SubmitChanges(failureMode);
}
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}
[Serializable]
public class ValidationException : Exception
{
public ValidationException(IEnumerable<ValidationResult> results)
: base("There are validation errors.")
{
this.Results = new ReadOnlyCollection<ValidationResult>(
results.ToArray());
}
public ReadOnlyCollection<ValidationResult> Results
{
get; private set;
}
}
Calling the Validate() method will return a collection of all errors, but rather than calling Validate(), I'd simply call SubmitChanges() when you're ready to persist. SubmitChanges() will now check for errors and throw an exception when one of the entities is invalid. Because the list of errors is sent to the ValidationException, you can iterate over the errors higher up the call stack, and present them to the user, as follows:
try
{
db.SubmitChanges();
}
catch (ValidationException vex)
{
ShowErrors(vex.ValidationErrors);
}
private static void ShowErrors(IEnumerable<ValidationResult> errors)
{
foreach(var error in errors)
{
Console.WriteLine("{0}: {1}", error.Key, error.message);
}
}
When you use this approach you make sure that your entities are always validated before saving them to the database
Here is a good article that explains how to integrate VAB with LINQ to SQL. You should definitely read it if you want to use VAB with LINQ to SQL.