views:

178

answers:

1

I am trying out Castle ActiveRecord. I want to use the Validation features AND the LINQ features.

In order to use LINQ, you can either:

  1. My preference: Make your entities inherit from ActiveRecordLinqBase<T>, then to query:

    var blogs = (from b in Blog.Queryable select b).ToList();

  2. Use ActiveRecordLinq.AsQueryable<T>, e.g.:

    var blogs = (from b in ActiveRecordLinq.AsQueryable() select b).ToList()

Now, to use the validation features, you have to make your entities inherit from ActiveRecordValidationBase<T>.

Multiple inheritance isn't supported so, here's my options:

  1. Use #2 from above while making my entities inherit from ActiveRecordValidationBase<T>. Disadvantage: LINQ statements are longer and uglier.
  2. Create a class that inherits from ActiveRecordLinqBase<T> and duplicates the code found in ActiveRecordValidationBase<T>. Disadvantage: Duplicate code, which must be updated with future ActiveRecord releases. Here's the class:

Edit: 3. (Not Tested) Simulate multiple inheritance. Disadvantage: Have to keep Property and Method Definitions in sync with updates.

 

using System;
using System.Collections;
using System.Xml.Serialization;
using Castle.ActiveRecord.Framework;
using Castle.Components.Validator;
using NHibernate.Type;

namespace Castle.ActiveRecord.Linq
{
    [Serializable]
    public abstract class ActiveRecordValidationLinqBase<T> : ActiveRecordLinqBase<T>, IValidationProvider where T : class
    {
        // Fields
        [NonSerialized]
        private IValidationProvider _actualValidator;

        // Methods
        protected ActiveRecordValidationLinqBase() { }

        protected override bool BeforeSave(IDictionary state)
        {
            if (!this.IsValid(RunWhen.Insert))
            {
                this.OnNotValid();
            }
            return base.BeforeSave(state);
        }

        public virtual bool IsValid()
        {
            return this.ActualValidator.IsValid();
        }

        public virtual bool IsValid(RunWhen runWhen)
        {
            return this.ActualValidator.IsValid(runWhen);
        }

        protected override bool OnFlushDirty(object id, IDictionary previousState, IDictionary currentState, IType[] types)
        {
            if (!this.IsValid(RunWhen.Update))
            {
                this.OnNotValid();
            }
            return base.OnFlushDirty(id, previousState, currentState, types);
        }

        protected virtual void OnNotValid()
        {
            ActiveRecordValidator.ThrowNotValidException(this.ValidationErrorMessages, this.PropertiesValidationErrorMessages);
        }

        // Properties
        [XmlIgnore]
        protected virtual IValidationProvider ActualValidator
        {
            get
            {
                if (this._actualValidator == null)
                {
                    this._actualValidator = new ActiveRecordValidator(this);
                }
                return this._actualValidator;
            }
        }

        [XmlIgnore]
        public virtual IDictionary PropertiesValidationErrorMessages
        {
            get
            {
                return this.ActualValidator.PropertiesValidationErrorMessages;
            }
        }

        public virtual string[] ValidationErrorMessages
        {
            get
            {
                return this.ActualValidator.ValidationErrorMessages;
            }
        }
    }
}

Is there a better way?

+2  A: 

to use the validation features, you have to make your entities inherit from ActiveRecordValidationBase.

Not necessarily. Validation is a separate Castle project, it's not very tightly coupled to ActiveRecord. You can run the validation manually. By manually I mean wrapping this in your own repository/DAO class.

And since it's loosely coupled you could even choose any other validation framework.

Personally, I don't consider ActiveRecordLinq<Blog>.AsQueryable() to be much longer or uglier than Blog.Queryable so I'd go with that option.

Mauricio Scheffer