1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.ActiveRecord
18 using System
.Collections
;
19 using System
.Collections
.Generic
;
20 using System
.Reflection
;
21 using Castle
.ActiveRecord
.Framework
.Internal
;
22 using Castle
.Components
.Validator
;
25 /// Extends <see cref="ActiveRecordBase"/> adding automatic validation support.
26 /// <seealso cref="ActiveRecordValidationBase.IsValid()"/>
30 /// public class Customer : ActiveRecordBase
34 /// [Property, ValidateNotEmpty]
37 /// get { return _name; }
38 /// set { _name = value; }
41 /// [Property, ValidateNotEmpty, ValidateEmail]
44 /// get { return _email; }
45 /// set { _email = value; }
50 public abstract class ActiveRecordValidationBase
<T
> : ActiveRecordBase
<T
> where T
: class
53 private ValidatorRunner __runner
= new ValidatorRunner(ActiveRecordModelBuilder
.ValidatorRegistry
);
55 [System
.Xml
.Serialization
.XmlIgnore
]
56 private IDictionary __failedProperties
;
59 /// Constructs an ActiveRecordValidationBase
61 public ActiveRecordValidationBase()
66 /// Performs the fields validation. Returns true if no
67 /// validation error was found.
69 /// <returns></returns>
70 public virtual bool IsValid()
72 return IsValid(RunWhen
.Everytime
);
76 /// Performs the fields validation for the specified action.
78 /// <param name="runWhen">Use validators appropriate to the action being performed.</param>
79 /// <returns>True if no validation error was found</returns>
80 public virtual bool IsValid(RunWhen runWhen
)
82 __failedProperties
= new Hashtable();
86 __runner
= new ValidatorRunner(ActiveRecordModelBuilder
.ValidatorRegistry
);
89 bool returnValue
= __runner
.IsValid(this, runWhen
);
91 foreach (PropertyInfo propinfo
in ActiveRecordValidationBase
.GetNestedPropertiesToValidate(this))
93 object propval
= propinfo
.GetValue(this, null);
97 bool tmp
= __runner
.IsValid(propval
, runWhen
);
99 __failedProperties
.Add(propinfo
,
100 new ArrayList(__runner
.GetErrorSummary(propval
).GetErrorsForProperty(propinfo
.Name
)));
107 Type type
= GetType();
108 ErrorSummary summary
= __runner
.GetErrorSummary(this);
110 foreach (string property
in summary
.InvalidProperties
)
112 __failedProperties
.Add(type
.GetProperty(property
), new ArrayList(summary
.GetErrorsForProperty(property
)));
120 /// Returns a list of current validation errors messages.
122 public virtual String
[] ValidationErrorMessages
126 if (__runner
== null)
128 __runner
= new ValidatorRunner(ActiveRecordModelBuilder
.ValidatorRegistry
);
131 if (__runner
.GetErrorSummary(this) == null)
136 List
<string> errorMessages
= new List
<string>(__runner
.GetErrorSummary(this).ErrorMessages
);
138 ActiveRecordValidationBase
.AddNestedPropertyValidationErrorMessages(errorMessages
, this, __runner
);
140 return errorMessages
.ToArray();
145 /// Maps a specific PropertyInfo to a list of
146 /// error messages. Useful for frameworks.
148 [System
.Xml
.Serialization
.XmlIgnore
]
149 public virtual IDictionary PropertiesValidationErrorMessage
151 get { return __failedProperties; }
155 /// Override the base hook to call validators required for create.
157 /// <param name="state">The current state of the object</param>
158 /// <returns>Returns true if the state has changed otherwise false</returns>
159 protected internal override bool BeforeSave(IDictionary state
)
161 if (!IsValid(RunWhen
.Insert
))
166 return base.BeforeSave(state
);
170 /// Override the base hook to call validators required for update.
172 /// <param name="id">object id</param>
173 /// <param name="previousState">The previous state of the object</param>
174 /// <param name="currentState">The current state of the object</param>
175 /// <param name="types">Property types</param>
176 /// <returns>Returns true if the state has changed otherwise false</returns>
177 protected internal override bool OnFlushDirty(object id
, IDictionary previousState
, IDictionary currentState
, NHibernate
.Type
.IType
[] types
)
179 if (!IsValid(RunWhen
.Update
))
184 return base.OnFlushDirty(id
, previousState
, currentState
, types
);
188 /// Throws an exception explaining why the save or update
189 /// cannot be executed when fields are not ok to pass.
192 /// You can override this method to declare a better behavior.
194 protected virtual void OnNotValid()
196 throw new ValidationException(
197 "Can't save or update as there is one (or more) field that has not passed the validation test",
198 ValidationErrorMessages
);