Wednesday, December 31, 2008

DBObject

I made some changes so I could display code on the site. Thanks to This guy


below is a basic working starting point for the DBObject. It does one very important thing. It can fill it's self out from a DataReader.


///
/// This is the baseclass for DB Object created by Chris Richards
///

[Serializable]
public class DBObject
{
//Holds all the properties in the object
protected Hashtable _properties = new Hashtable();

private string _select_query;
private PropertyInfo[] _obj_proterties;

///
/// An Array of all the properities for this object
///

private PropertyInfo[] _propteries_
{
get
{
if (_obj_proterties == null)
{
_obj_proterties = this.GetType().GetProperties();
}
return _obj_proterties;
}
}


///
/// Gets the SELECT ... FROM query for this object
///

protected string SelectQuery
{
get
{
if (_select_query == string.Empty || _select_query == null)
{
//Generate the Select Query
_select_query = "SELECT";
//Get Information about the object
object[] obj_attributes = this.GetType().GetCustomAttributes(false);

//Now Set all the select columns
foreach (PropertyInfo properity in this._propteries_)
{
object[] attributes = properity.GetCustomAttributes(false);
foreach (object attribute in attributes)
{
if (attribute is DBColumn)
{
_select_query += " " + ((DBColumn)attribute).Column + ",";
}
}
}

//Remove the last Comma
_select_query = _select_query.Substring(0, _select_query.Length - 1);

//Get the Table Name for this Object
foreach (object attr in obj_attributes)
{
if (attr is DBTable)
{
//Add the Table to our List
_select_query += " FROM " + ((DBTable)attr).Table;
}
}
}

return _select_query;
}
}



protected DBObject() { }

///
/// This will populate the object from the reader.
/// It will not advance the reader.
///

protected void FromReader(MySqlDataReader reader)
{
//Look for all the properities
foreach (PropertyInfo properity in this._propteries_)
{
if (properity.CanWrite)
{
object[] attributes = properity.GetCustomAttributes(false);
foreach (object attribute in attributes)
{
if (attribute is DBColumn)
{
try
{
properity.SetValue(this, reader[((DBColumn)attribute).Column], null);
}
catch (IndexOutOfRangeException)
{
//Just Skip it
}
catch (Exception ex)
{
//ErrorLog.Log(-1, this.GetType().Name + " reader Error", ex.Message);
string junk = ex.Message;
}
}
}
}
else
{
ErrorLog.Log(-1, "Can't Write " + this.GetType().Name + "'s Properity", "Properity: " + properity.Name);
}
}
}
}

Monday, December 15, 2008

School is almost over!

I haven't worked on this project since school started. It's finals week so I thought I should start this project again.

I think I may have bitten off more than I can chew with this project. It's become larger and more complicated than I initially imagined. So the first step is to review the goal of the project.

Goal:
To make developing Database Objects easier by having many of the details taken care by the object it's self. A developer with little skill should be able to create an object that inherits from the DBObject and start using it.

Step 1:
I find the most repetitive part of developing database objects has been filling out the object. I have to make a loop to read the DataReader, and convert the columns to their proper types before assigning them to the object.

I could have a lot of time and error prone code, if the object would preform this task it's self.

So this is where I'm going to restart. If I remember correctly, I either almost had this functionality already, or was very close to having it. Once I've verified it, then I can think about step 2.

Thursday, August 7, 2008

Design

Something that I just realized that's going to be important. I need to be able to get result sets by a Property. For example: user.BySex("male");

With the way I've been going I'm not sure how this will fit into the model, but it's a feature that must exist.

Maybe something like Factory<user>("Sex = ?1", "male");
I guess that works, maybe I'm thinking there is something missing where there isn't.

Tuesday, August 5, 2008

Generics Issues

I've never really used Generics before so I'm still struggling with it.
What I think I want to do, is have a method that returns List;. I can return the list ok, and I can use Activator to create new T objects. The only problem is that my test requires some boxing, which is what I want to avoid. I'm wondering if the boxing will disappear in a real world example.

test code



using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace GenericsTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Test 1");
Factory fact = new Factory();
List<obint>; test1 = fact.GetList<obint>();
foreach (ObInt item in test1)
{
Console.WriteLine(item.Data);
}

Console.WriteLine("\nTest Two");
List<int> test2 = new List<int>();
test2.Add(1);
test2.Add(2);
test2.Add(3);
foreach (int item in test2)
{
Console.WriteLine(item);
}

Console.WriteLine("Done, hit anykey");
Console.Read();

}
}

//The Goal is to see if I can return a Generic list
public class Factory
{
public List<t> GetList<t>() where T : IObject
{
List<t> list = new List<t>();

T tmp = Activator.CreateInstance<t>();
tmp.Add(5);

list.Add(tmp);

return list;
}
}

public interface IObject
{
void Add(object item);
}

public class ObInt : IObject
{
protected int _data;
public int Data
{
get { return _data; }
set { _data = value; }
}

public ObInt(int data)
{
_data = data;
}
public ObInt() { }

public void Add(object item)
{
_data = (int)item;
}

}

public class ObString: IObject
{
protected string _data;
public string Data
{
get { return _data; }
set { _data = value; }
}

public ObString(string data)
{
_data = data;
}
public ObString() { }

public void Add(object item)
{
_data = item.ToString();
}
}
}

Monday, August 4, 2008

Problem, Expected

I ran into a problem when trying to get the object to return a list. This has given me time to kinda rethink some of the choices I've made.
I've never liked the internal object, but didn't know of a way I would like better. I'm wondering if it would be better to have Methods to get the internal information instead of Properties. So I could call something like self.Column("Name"); and it would return a column name that was associated with the Propriety Name. Table could still be a Property, I see no reason why it shouldn't be.
While looking at other implementations of database object I've seen that they normally have a kind of master DB object. So you can do things like users = db.Select( "SELECT * FROM user"); (I'm looking towards Google's app engine here.) I don't have any core object in my design. I'm not sure if that is a good thing or not.
A problem I ran into so having to have an object already to call it's select. A Factory object would help with this. Something like DBFactory.Select( User, "Name = ?1", "Chris" ) would be nice. As long as I'm thinking about this route, List myusers = DBFactory.Select( typeof(User), "Age >= ?1 AND employed = ?2", 21, true ); Might be Idea. This is inspired by google's model. The only down side is that I can't build in custom filters on the list. So Instead of getting one list of all users over 21 and being able to get just the employed and then just the unemployed without ever making another DB call. The user has to either do the filter themselves, or (more likely) make the DB call twice (eww).
On the otherhand, if the DBFactory was global, it could keep a cache of the results it's returned and do the filter itself?

Thursday, July 31, 2008

Generics List or Custom List

I've been thinking about whether the DBObject should use generics for returning lists or use a custom list object. I think from a coding perspective generics would seem like the easier choice. The DBObject user could just return List and presto you have a list of users! The down side is that you can't add custom functions to the List object. Using the custom list we can create UserList: CollectionBase This would give us a list of user objects that we can add our own methods to.

Why do I think custom methods on the list are important? To prevent unnecessary calls to the Database. With UserList I could get all the users in a project, and then filter out just what I need for each control. Example:

UserList users = users.ByProject(5);
DropDownList active.DataSource = users.Active();
Repeater r_Newest = users.Newest(10);

So instead of making two Database calls for Active users and Newest users, I made one database call and just filtered the data I was looking for. I think this is very important to have as the applications scales.
On the other hand I could do something like make the DBObject keep a cache of it's own data. That just feels like a problem waiting to happen. The only way I can conceive of that is to have an Object Factory

For now I'm just going to stick with the custom lists

Thursday, July 17, 2008

.Select()

What I would like to be able to do is something like: UserList = User.Select( AND( LIKE( User.Email, "%gmail.com" ), EQUALS( User.Active, true ) ) ) That way it would be easy to construct whatever select statement is necessary. (I haven't taking multiple tables into account yet.)

I've been thinking about how to actually program this. One thing I found out was that I can't (or I haven't found a way) to send the property of an object without doing a much of extra steps. But what I can do is send the object and the name of the property. So it becomes EQUALS( User, "Active", true )
The other down side is that those functions ( ADD, LIKE, EQUALS ) need to be part of an object... Unless they are Objects themselves. I'm not too found of having the call be something like UserList = User.Select( Selector.AND( Selector.LIKE( User, "Email", "%gmail.com" ), Selector.EQUALS( User, "Active", true ) ) ) I found it annoying to have to have the object name in front of each.

If I made them objects on the other hand, I wouldn't have that problem...

Internal

After writing

PropertyInfo[] obj_properities = this.GetType().GetProperties();
foreach (PropertyInfo prop in obj_properities)
{
//Is this the Properity we are looking for?
if (prop.Name == properity)
{
//Get the Attributes on the Properity
object[] prop_attributes = prop.GetCustomAttributes(true);
foreach (object attribute in prop_attributes)
{
//Is this the Column Name?
if (attribute is DBColumn)
{
//Do Something
break;
}
}
}
}

For the millionth time (or more like 3rd or 4th) I thought it would be nice if the object could provide this information for me. The problem was that I need my Selector object to be able to access this information as well (and I don't want the Selector Object to inherit from DBObject). So I Created another object with some of the information I use more often called Internal (I don't like the name but couldn't think of what else to call it.)

The Problem with this was that I didn't want everyone to be able to call these internal methods. So I created an InternalAttribute, and the Internal object checks that the caller has the InternalAttribue before it'll return any information. This isn't a perfect solution (I'd rather the methods never show up at all) but it seems to work so far.

Wednesday, July 16, 2008

DBObject

I haven't posted in a while (a year!) I'm working on a .Net project to create a set of MySql Objects. I'm basing this design off of python's SQLObject.

The idea is to create an Object that inherits from DBObject, then set attributes to denote the table and the columns.

Example:

[DBTable("user")]
public class User : DBObject {
[DBColumn("first_name")]
public string FirstName
{
get { return (string)List["first_name"]; }
set
{
List["first_name"] = value;
_dirty = true;
}
}
}


DBObject would provide some automatic functions like .ByID which will return an object by it's key. Example: User myuser = User.ByID(1);
And .Update() Which will update all the Properties with an Attribute of DBColumn. But it only updates if the object has been marked as dirty (_dirty=true;)


I also want to add a .Select() that allows you to create your own queries. Since you define the object you can define whatever logic the object should have. This helps keep ASP.NET in M.V.C.