posts - 26, comments - 18, trackbacks - 0, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

自己动手写ORM框架第一步

Posted on 2008-05-09 21:01 Jerson Ju 阅读(189) 评论(2)  编辑 收藏 网摘 所属分类: asp.net
         现在我用一个小的Demo来模拟ORM基本原理。水平有限,大师级别闪过。这东西本来是3年前写ORM框架后,从中软国际回到长沙做软件教学跟学生讲座用的。结果一直没用上。当今软件培训的生源基础不敢恭维,所以我一直没用上。估计讲了他们也会以为我是个疯子。所以我不当老师了,这两天失业中,无聊。写写博客,本想写控件开发,发现无数大师已经写得够全够好了。废话不多说了。开始了。
       ORM是帮我们做什么的?当我们调用ORM的方法,ORM框架根据我们的实体类和我们的条件生产SQL语句,然后执行。现在我就来一步一步模拟。Super类是我模拟的框架,这个类编译成DLL了。假设框架已经存在了,现在我们来使用这个框架。
跟使用其他ORM框架一样,我们生成一个实体类与数据库表对应。
    public class Person:Super
    {
        
private int id;
        
public int ID
        {
            
get
            {
                
return this.id;
            }
            
set
            {
                
this.id=value;
            }
        }
    }

我们再生成一个XML映射文件

<?xml version="1.0" encoding="utf-8" ?> 
<map>
    
<class name="Person">
        
<attribute name="ID"/>
    
</class>
</map>

后面会讲为什么需要这两个文件,先别急。现在我们来做数据插入操作。

        static void Main(string[] args)
        {
           Person s
=new Person();
            s.ID
=500;
            s.save();

        }

这样,数据就插入数据库了。Save哪里来的?Person继承了Super,Save是从Orm框架里来的.Super类在Super.dll里,我们现在使用它是引用它,根本没它的源代码。当我们调用Save方法,Save帮我们做了几件事情。
1、获得Person对象在数据库中的表名
2、获得ID字段名
3、获得ID被赋予的值是多少
4、然后生产Insert into 表名 values(id属性的值) 插入数据库
Super.dll是我N年前写的,我那时怎么知道,你的表名,字段,你赋予的值是多少,我怎么帮你生成SQL啊?
我写Super.dll时候,上面需要的4个东西,我都没有。那怎么办呢?
好莱坞不是电影里:“你不来找我,我就来找你”。呵呵
我无法知道,所以你写代码时候,你主动告诉我。所以就是你为什么要写实体类和XML映射文件的原因。
1.xml是你把你的数据表名和字段名写在里面。
2.实体类,你等下你对属性赋值后,我在N年前就在Super类里读取你的Xml里的字段,然后对实体类反射获得你的属性的值。
这样我能在Super类里得到上面需要的 表名 字段名  和你 实体对象的属性值。那么我是不是可以拼凑sql执行了啊。

下面我们来看Super类的代码。

    public class Super
    {

        
public static string GetClassName(Type classType)//获得对象的type为反射做准备
        {
            
string name=classType.ToString();
            
return name.Substring(name.LastIndexOf('.')+1);
        }

        
public virtual string GetClassName()
        {
            
string name=this.ToString();
            
return name.Substring(name.LastIndexOf('.')+1);
        }
        
internal object GetAttributeValue(string name))//根据字段名,反射调用属性get方法,获得属性的值

        {
            Type attributeType
=this.GetType();
            
object rObject=null;
            
try
            {
                rObject
=attributeType.InvokeMember(name,BindingFlags.GetProperty,null,this,null);
            }
            
catch (Exception ex)
            {
             Console.WriteLine(ex);
            }
            
return rObject;
        }

        
internal void SetAttributeValue(string name,object objValue)//根据字段名,反射调用属性set方法
        {
            Type attributeType
=this.GetType();
            
object[] objectsValue=new object[1];
            objectsValue[
0]=objValue;
            
try
            {
                attributeType.InvokeMember(name,BindingFlags.SetProperty,
null,this,objectsValue);
            }
            
catch
            {            
            }
        }

        
public string getAttributeNameByXml()//通过读取XML获得表名,字段名,我这里写死了,你可以在Super里写个属性,要用户在调用Save前,把xml地址赋值给Super
        {
            XmlDocument oxmlDocument
=new XmlDocument();
            oxmlDocument.Load(
@"C:\Documents and Settings\zhujian\Desktop\ParentCallSub\ParentCallSub\objMap.xml");
            XmlNodeReader rd
=new XmlNodeReader(oxmlDocument);
            
while(rd.Read())
            {
                
if(rd.NodeType!=XmlNodeType.Element) continue;


                
if(rd.Name.ToLower()=="attribute")
                {
                    
return rd.GetAttribute("name").ToString();
                }
            }
            
return null;
        }


        
public void save()//我模拟的数据保存方法,为了Demo简单,我只做个打印
        {

            
object obj = GetAttributeValue(getAttributeNameByAttribute());
                    Console.WriteLine(obj.ToString());
        
        }
    }

ORM模拟完毕了。呵呵,是不是很简单啊。

上面是通过xml方式告诉Super 框架,字段表名。
还有通过attribute自定义元属性方式,在代码的属性和类名上直接配置。这样就省去了XML文件。现在JAVA也有这东西了,以前是C#自豪的地方。ActiveRecord、Linqtosql等都支持元属性标记的。


自定义attribute,来标记字段。
    [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
    
public class SelfField:Attribute
    {
        
private string column;

        
public SelfField(string column)
        {
            
this.column=column;
        }
        
public string Column
        {
            
get
            {
              
return this.column;
            }
        }
    }

现在来改下Super类,让它支持attribute标记。

    public class Super
    {

        
public static string GetClassName(Type classType)
        {
            
string name=classType.ToString();
            
return name.Substring(name.LastIndexOf('.')+1);
        }

        
public virtual string GetClassName()
        {
            
string name=this.ToString();
            
return name.Substring(name.LastIndexOf('.')+1);
        }
        
internal object GetAttributeValue(string name)
        {
            Type attributeType
=this.GetType();
            
object rObject=null;
            
try
            {
                rObject
=attributeType.InvokeMember(name,BindingFlags.GetProperty,null,this,null);
            }
            
catch (Exception ex)
            {
             Console.WriteLine(ex);
            }
            
return rObject;
        }

        
internal void SetAttributeValue(string name,object objValue)
        {
            Type attributeType
=this.GetType();
            
object[] objectsValue=new object[1];
            objectsValue[
0]=objValue;
            
try
            {
                attributeType.InvokeMember(name,BindingFlags.SetProperty,
null,this,objectsValue);
            }
            
catch
            {            
            }
        }

        
public string getAttributeNameByAttribute()//这里就是改动的,现在这里是通过反射,读取attribute属性获得表名和字段的。
        {
            Type t
=this.GetType();
            
foreach(PropertyInfo pInfo in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
            {
               SelfField[] fieldArr
=(SelfField[])pInfo.GetCustomAttributes(typeof(SelfField),true);
                SelfField field
=fieldArr.Length>0?fieldArr[0]:null;
                
if(field!=null)
                {
                    
return field.Column;
                }
            }

            
return null;
        }

        
public void save()
        {

            
object obj = GetAttributeValue(getAttributeNameByAttribute());
                    Console.WriteLine(obj.ToString());
        
        }
    }

上面是改进后的框架代码,我们现在来使用这个框架。
同样,实体类
    public class Bsub:Super
    
{
        
private int id;

        [SelfField(
"ID")]//这里比上次多了个标记了。呵呵
        public int ID
        
{
            
get
            
{
                
return this.id;
            }

            
set
            
{
                
this.id=value;
            }

        }

    }
接下来,Main函数。
        static void Main(string[] args)
        {
           Bsub s
=new Bsub();
            s.ID
=800;
            s.save();

        }

大功告成!写的途中IE挂了一次,这是写第二遍了。希望这篇文章没有浪费你宝贵的时间。别扔鸡蛋啊,石头什么的。                                                                                     
                                                                                               作者:朱剑
                                                                                               2008年5月9号
                                                                      纯属技术交流,转载请保留文章完整,标明出处。

Feedback

#1楼    回复  引用    

2008-07-14 13:58 by 小徐。。。 [未注册用户]
我对你的框架很感兴趣。。。不知道能不能提供更加详细的例子,最好是操作数据库的例子,有的话:xqxujun@tom.com 万分感谢

#2楼 [楼主]   回复  引用  查看    

2008-08-21 18:58 by Jerson Ju      
谢谢,终于看到识货的兄弟了。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

相关文章:

相关链接: