DBObject with Self Updating.

I’ve added self updating and Insert to the DBObject. I’ve also changed the naming of the columns it pulls from the database. Each column property now starts with “column_”.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using MySql.Data.MySqlClient;

namespace ZenSoftware
{
    /// <summary>
    /// Base object for ORM Objects
    /// </summary>
    public class DBObject
    {
        protected Hashtable _properties;

        protected DBObject()
        {
            _properties = new Hashtable();
        }

        /// <summary>
        /// Get a property in the object if it exits. If not use the default_value instead.
        /// </summary>
        /// <param name="name">Name of the Property</param>
        /// <param name="default_value">Value to use if the property doesn't exist.</param>
        /// <returns></returns>
        public object GetProperty(string name, object default_value)
        {
            //Check if it exists yet
            if (!_properties.ContainsKey(name))
            {
                _properties[name] = default_value;
            }
            return _properties[name];
        }
        /// <summary>
        /// Get a property in the object if it exits. If not use the default_method to get one.
        /// </summary>
        /// <param name="name">Name of the Property</param>
        /// <param name="default_method">Method to call if the property doesn't exist.</param>
        /// <returns></returns>
        public object GetProperty(string name, Func<object> default_method)
        {
            //Check if it exists yet
            if (!_properties.ContainsKey(name))
            {
                _properties[name] = default_method();
            }
            return _properties[name];
        }
        /// <summary>
        /// Get a property from the object.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetProperty(string name, object value)
        {
            _properties[name] = value;
        }
        /// <summary>
        /// Will return true if the value is Different from the stored property
        /// </summary>
        /// <param name="name">Name of Property</param>
        /// <param name="value">Value check the Property</param>
        protected bool isPropertyDifferent(string name, object value)
        {
            //Check if it exists yet
            if (_properties.ContainsKey(name))
            {
                //Check if it's different
                if (_properties[name] == value)
                {
                    return false;
                }
            }
            //It's different or it doesn't exist.
            return true;
        }

        /// <summary>
        /// Fill out our properties from the command.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="connection"></param>
        protected void Fill(MySqlCommand command, string connection)
        {
            using (MySqlConnection conn = new MySqlConnection(connection))
            {
                //Connect the command to the connectiong
                command.Connection = conn;

                try
                {
                    //Open the connection and get the reader
                    conn.Open();
                    MySqlDataReader reader = command.ExecuteReader();

                    //I only want to get the frist record because I'm returning just one object.
                    while (reader.Read())
                    {
                        //Get all the columns
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            this.SetProperty("column_" + reader.GetName(i), reader[i]);
                        }
                    }

                }
                catch (Exception ex)
                {
                    Console.WriteLine("\nError:\n" + ex.Message);
                }

            }
        }

        /// <summary>
        /// index_column is the column to use in the WHERE clause. The object expects something like "id"
        /// All columns to updated *must* start with "column_" in the Properties (this is done automatically if you used the object.)
        /// </summary>
        /// <param name="connection"></param>
        public void Update(string table, string index_column, string connection)
        {
            if (this._properties.Count > 0 && this._properties.ContainsKey("column_" + index_column))
            {
                //Build our Command
                MySqlCommand cmd = new MySqlCommand();
                //Build the query
                StringBuilder sb_query = new StringBuilder();
                sb_query.Append("UPDATE ");
                sb_query.Append(table);
                sb_query.Append(" SET ");

                //Add all of the properties
                foreach (string key in this._properties.Keys)
                {
                    //If it's a column and it's not the id
                    if (key.StartsWith("column_") && key != "column_" + index_column)
                    {
                        //Cool, lets add the key
                        sb_query.Append(key.Substring(key.IndexOf("_") + 1));
                        sb_query.Append("=");
                        sb_query.Append("?" + key);
                        sb_query.Append(", ");
                        //Now add the value
                        cmd.Parameters.AddWithValue("?" + key, this._properties[key]);
                    }
                }
                //Now remove the  trailing comma
                sb_query.Remove(sb_query.Length - 2, 2);

                //Add the WHERE
                sb_query.Append(" WHERE ");
                sb_query.Append(index_column);
                sb_query.Append("=?column_");
                sb_query.Append(index_column);
                cmd.Parameters.AddWithValue("?column_" + index_column, this._properties["column_" + index_column]);

                //Start the Database stuff
                using (MySqlConnection conn = new MySqlConnection(connection))
                {
                    //Put the Command together
                    cmd.CommandText = sb_query.ToString();
                    cmd.Connection = conn;

                    //Now run it!
                    try
                    {
                        conn.Open();
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("\nError:\n" + ex.Message);
                    }
                }
            }
        }

        /// <summary>
        /// Inserts all properties who's name starts with "column_" into the database.
        /// It will then set it's own index_column property with the new index value.
        /// </summary>
        /// <param name="table">Table to insert.</param>
        /// <param name="index_column">expects something like "id".</param>
        /// <param name="connection">Database Connection String.</param>
        public void Insert(string table, string index_column, string connection)
        {
            if (this._properties.Count > 0)
            {
                //Build the command
                MySqlCommand cmd = new MySqlCommand();

                //Build the Query
                StringBuilder sb_query = new StringBuilder();   //First part of the query
                sb_query.Append("INSERT INTO ");
                sb_query.Append(table);
                StringBuilder sb_values = new StringBuilder(); //Second part of the query
                sb_values.Append("VALUES ");

                //Add the Columns to insert and their values
                sb_query.Append("(");
                sb_values.Append("(");
                foreach (string key in this._properties.Keys)
                {
                    //If it's a column and it's not the id
                    if (key.StartsWith("column_") && key != "column_" + index_column)
                    {
                        //Add the Column name
                        sb_query.Append(key.Substring(key.IndexOf("_") + 1));
                        sb_query.Append(",");

                        //Add the Value
                        sb_values.Append("?");
                        sb_values.Append(key);
                        sb_values.Append(",");
                        //Add the value to the command
                        cmd.Parameters.AddWithValue("?" + key, this._properties[key]);
                    }
                }
                //Now remove the  trailing comma
                sb_query.Remove(sb_query.Length - 1, 1);
                sb_query.Append(")");
                sb_values.Remove(sb_values.Length - 1, 1);
                sb_values.Append(")");

                //Start the Database stuff
                using (MySqlConnection conn = new MySqlConnection(connection))
                {
                    //Put the Command together
                    cmd.CommandText = sb_query.ToString() + " " + sb_values.ToString();
                    cmd.Connection = conn;

                    //Now run it!
                    try
                    {
                        conn.Open();
                        cmd.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("\nError:\n" + ex.Message);
                    }
                }

                //Now lets get the ID back
                // TODO: This could return the wrong id. We need to verify that the columns are the ones we just inserted.
                MySqlCommand cmdID = new MySqlCommand("SELECT " + index_column + " FROM " + table + " ORDER BY id DESC LIMIT 1");
                this.Fill(cmdID, connection);
            }
        }

        /// <summary>
        /// Get just a single object by a select command.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="connection"></param>
        /// <returns></returns>
        static protected T SingleBySelect<T>(MySqlCommand command, string connection)
        {
            //Use the list, just return a single item though
            List<T> list = DBObject.BySelect<T>(command, connection);
            if (list.Count > 0)
            {
                return list[0];
            }
            else
            {
                return default(T);
            }
        }

        /// <summary>
        /// Get a list of T Objects from a query.
        /// The objects will have properties for every column specified by the query.
        /// The Property names will be "column_" + column_name.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="connection"></param>
        /// <returns></returns>
        static protected List<T> BySelect<T>(MySqlCommand command, string connection)
        {
            List<T> list = new List<T>();
            using (MySqlConnection conn = new MySqlConnection(connection))
            {
                //Connect the command to the connectiong
                command.Connection = conn;

                try
                {
                    //Open the connection and get the reader
                    conn.Open();
                    MySqlDataReader reader = command.ExecuteReader();

                    //I only want to get the frist record because I'm returning just one object.
                    while (reader.Read())
                    {
                        T obj = System.Activator.CreateInstance<T>();
                        //Get all the columns
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            //Get the name and the value
                            object[] parms = { "column_" + reader.GetName(i), reader[i] };
                            //Get the SetProperty Method and Call it
                            MethodInfo method = obj.GetType().GetMethod("SetProperty");
                            method.Invoke(obj, parms);
                        }
                        //Add it to the list
                        list.Add(obj);
                    }

                }
                catch (Exception ex)
                {
                    Console.WriteLine("\nError:\n" + ex.Message);
                }

            }
            return list;
        }

    }
}

Update:

Ran into an unexpected problem. I used a bigint for my id column and was getting a conversion error when I ran the code. I thought bigint could be cast into int. I was wrong. bigint is cast to Int64. With this changed everything worked as expected.

It would also be nice if there was a way to check for duplicate records before inserting. Sometimes I might want to allow duplications, but the most of the time I don’t want them.

Share

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv Enabled