The idea of Recorders

NHibernate and other ORM projects wrap database entities within mapping classes. According to DTO/DAO pattern: the DAO is a class that usually has the CRUD operations like save, update, delete... whereas the DTO is just an object that holds data.

To start querying the database in business way we need something more... something between DAO and DTO objects... something responsible for retrieving data only (like DAO) but also very flexible. In NHibernate Criteria Builder we use Recorders for that:

Recorder is a object that behaves like DAO (can load specified type of data DTO from the database) but also represents all the available connections between other recorders. This connections maps relationships between database tables

Recorders of NHibernate Criteria Builder are just wrappers around DTO classes that record/collect every user expectation about the data he/she wants to get from the database (so I called these wrappers: RECORDERS)!
Because Recorder contains the information how entities are connected each other (and exposes this connections as properties) user can focus only on specifying what kind of data he/she wants to retrieve without getting into primary key/ foreign key details.

Example: Recorder of Company DTO (see example database schema) you can use this code as a recorder template in your project
    /// <summary>
    /// Recorder Template
    /// <remarks>
    /// Derive from: CriteriaRecorder<R,T>
    ///     R - type of Recorder for merging purpose (the same class as the recorder)
    ///     T - type of DTO object being wrapped
    /// </remarks>
    /// </summary>
    [Serializable]
    public class CompanyRec : CriteriaRecorder<CompanyRec,Company>
    {
        /*********************************************************
         * DTO IDENTIFIER
         * Map identifier property as every single recorder property
         * When the name of DTO property storing Identifier is different 
         * than "Id", overwrite GetIdPropertyName() method of CriteriaRecorder<R,T>        
         * 
         * public override string GetIdPropertyName()
         * {
         *     return "IdPropertyName";
         * }
         ********************************************************/

        private ICriterionProperty<int> _Id;

        /// <summary>
        /// Recorder property for Id column - Example of Identifier mappings
        /// There's no need to override GetIdPropertyName() cause the
        /// name of Identifier property is equal to "Id"
        /// </summary>
        public ICriterionProperty<int> Id
        {
            get
            {
                if (this._Id == null)
                {
                    this._Id = new CriterionProperty<int>("Id", this);
                }

                return _Id;
            }
        }

        /*********************************************************
         * SIMPLE PROPERTIES
         * Map every simple property of your DTO object as 
         * ICriterionProperty<T>
         *     T - type of data stored in database entity/column
         *********************************************************/

        private ICriterionProperty<string> _Name;
        private ICriterionProperty<string> _City;


        /// <summary>
        /// Recorder property for Name column - Example of Simple Property mappings
        /// </summary>
        public ICriterionProperty<string> Name
        {
            get
            {
                if (this._Name == null)
                {
                    this._Name = new CriterionProperty<string>("Name", this);
                }

                return _Name;
            }
        }

        /// <summary>
        /// Recorder property for City column
        /// </summary>
        public ICriterionProperty<string> City
        {
            get
            {
                if (this._City == null)
                {
                    this._City = new CriterionProperty<string>("City", this);
                }

                return _City;
            }
        }   

        /*********************************************************
         * ONE-TO-MANY
         * Map every one-to-one and one-to-many relationship as
         * ISubcriteriaProperty<R>
         *     R - related subrecorder type
         *********************************************************/
        private ISubcriteriaProperty<EmployeeRec> _EmployeesByCompany;

        /// <summary>
        /// Recorder property of many-to-many relationship between Employees and Companies tables
        /// </summary>        
        public virtual ISubcriteriaProperty<EmployeeRec> EmployeesByCompany
        {
            get
            {
                if (this._EmployeesByCompany == null)
                {
                    this._EmployeesByCompany = new SubcriteriaProperty<EmployeeRec>("Company");
                }

                return _EmployeesByCompany;
            }
        }    


        /*********************************************************
         * ONE-TO-ONE, ONE-TO-MANY
         * Map every one-to-one and one-to-many relationship as
         * reference to related Recorder
         * Use "this" object as a parent of subrecorder like
         *********************************************************/

        private CountryRec _CountryRec;

        /// <summary>        
        /// Recorder for one-to-many relations between Countries and Companies
        /// </summary>        
        public virtual CountryRec Country
        {
            get
            {
                if (this._CountryRec == null)
                {
                    this._CountryRec = new CountryRec(this);
                }

                return this._CountryRec;
            }
            set
            {
                if (this._CountryRec == null)
                {
                    this._CountryRec = value;
                }
                else
                {
                    throw new RecorderAlreadyCreatedException();
                }
            }
        }


        /*********************************************************
         * CONSTRUCTORS
         * Provide two constructors: the empty one and the one
         * setting the parent (derived from base class)
         *********************************************************/
        /// <summary>
        /// Constructor, creates the recorder with no parent
        /// <summary>
        public CompanyRec()
        {
        }

        /// <summary>
        /// Constuctor, creates CriteriaRecorder and sets its parent
        /// </summary>
        /// <param name="parent">Parent of this recorder</param>
        public CompanyRec(ICriteriaRecorder parent)
            : base(parent)
        {
        }
    }
}


You can always use Reverse Engineering to produce the recorders, look here.

Last edited Oct 20, 2008 at 9:41 AM by infomechanica, version 13

Comments

No comments yet.