一个ORM的实现(附源代码)

1  前言

经过一段时间的编写,终于有出来一个稳定的版本,期间考虑了多种解决方案也偷偷学了下园子里面大神们的作品。

已经有很多的ORM框架,为什么要自己实现一个?我的原因是在遇到特殊需求时,可以在ORM中加入特定的代码。如 :根据数据库的字段长度和可空性做基本的数据验证,在ORM中解决数据修改时的同步问题…

本文主要关注的是如何实现ORM方面,其它的大家可以参考以下两篇文章:

用T4 Template生成代码:参考此文,可以知道本ORM是如何根据数据库,生成实体层代码。有了这个基础,就可以看懂本文本中所有的T4模板。

DBHelper (支持事务与数据库变更):参考此文,可以知道本ORM是如何访问数据库,如何支持事务,分页和多种数据库。

2  实现方法

本文主要关注的蓝色ORM部分。

Model:定义了实体的基类。每一张表都会生成对应的实体并继承此类;

ModelMapping:定义了一张表的结构信息,其中包含了表名、主键、字段类型等。每一张表都会生成一个;

ModelMappingReflector: 在程序第一次运行时,反射所有ModelMapping的子类,并将其加入一个字典集合中;

DataAccess<T>: 此类的作用时,根据实体和实体的结构信息(ModelMapping),自动生成SQL来访问数据库(Add,Update,Delete);或将数据库中值加到实体上(GetModel,GetList)。此类帮我们做CRUD的工作,我们不再需要写每张表基本的增删改查的工作了,但仍需要写复杂业务的查询。每一张表都会生成一个空的dao类并继承此类。

此ORM的核心类就是DataAccess<T>, 下面我们就拿Add作为示例:

Add 操作代码

public int Add(T model)
{
    if (model == null)
    {
        throw new ArgumentNullException();
    }

    StringBuilder cmdText = new StringBuilder();
    cmdText.Append("INSERT INTO ").Append(modelMapping.TableName).Append(" (");
    cmdText.Append(string.Join(",", model.ColumnValues.Keys.ToArray()));
    cmdText.Append(") VALUES (@");
    cmdText.Append(string.Join(", @", model.ColumnValues.Keys.ToArray()));
    cmdText.Append(")");

    List<DbParameter> dbParms = new List<DbParameter>();
    foreach (var pair in model.ColumnValues)
    {
        dbParms.Add(DBHelper.CreateInDbParameter(string.Format("@{0}",pair.Key), modelMapping.ColumnDict[pair.Key].DbDataBype, pair.Value));
    }

    return this.ExecuteNonQuery(CommandType.Text, cmdText.ToString(), dbParms.ToArray());
}

当我们写这样的代码时User model=new User(); model.UserName时,实际上会向Model中ColumnValues集合中添加数据。而要生成一个INSERT SQL (INSERT INTO tablename (column1,colum2) VALUES (@column1,@column2)和添加插入参数,我们需要表名,列名,列值和列的类型。在列名和列值就存在于Model中的ColumnValues集合,而列的类型和表名,我们可以在ModelMapping中获取。

3   示例

static void Main(string[] args)
{
    TestORM();
    TestPaging();

    Console.ReadLine();
}

static void TestORM()
{
    UserDao dao = new UserDao();
    try
    {
        dao.BeginTransaction();
        // add model
        User mUser1 = new User();
        mUser1.ID = "1";
        mUser1.UserName = "Mike1";
        mUser1.UserPwd = "1234";
        mUser1.CreateBy = "System";
        mUser1.CreateDate = DateTime.Now;
        dao.Add(mUser1);

        Console.WriteLine("Create Model Successfully.");
        string cmdText = "SELECT * FROM TUser WHERE ID=‘1‘ ORDER BY ID;";
        List<User> list0 = dao.GetListBySQL(cmdText);
        foreach (User model in list0)
        {
            Console.WriteLine(model.UserName);
        }
        Console.WriteLine("Get List Successfully.");

        //嵌套事务
        UserDao dao2 = new UserDao();
        try
        {
            dao2.BeginTransaction();
            //update model
            User mUser2 = new User();
            mUser2.ID = "1";
            mUser2.UserName = "Mike.Jiang";
            mUser2.UserPwd = null;
            mUser2.CreateDate = null;
            dao.Update(mUser2);
            Console.WriteLine("Update Model Successfully.");

            User mUser3 = dao.GetModel("1");
            if (mUser3 != null)
                Console.WriteLine(mUser3.UserName);

            Console.WriteLine("Get Model Successfully.");
            dao2.CommitTransaction();
        }
        catch
        {
            dao2.RollbackTransaction();
        }

        dao.Delete("1");

        Console.WriteLine("Delete Model Successfully.");
        dao.CommitTransaction();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        dao.RollbackTransaction();
    }
}

static void TestPaging()
{
    UserDao dao = new UserDao();
    // add 100 user
    for (int i = 1; i <= 100; i++)
    {
        User mUser1 = new User();
        mUser1.ID = i.ToString();
        mUser1.UserName = "Mike" + i.ToString();
        mUser1.UserPwd = "1234";
        mUser1.CreateBy = "System";
        mUser1.CreateDate = DateTime.Now;
        dao.Add(mUser1);
    }

    string cmdText = string.Format("SELECT * FROM TUser");
    DataTable table = DBHelper.ExecutePagingDataTable(CommandType.Text, cmdText, 1, 10, "ORDER BY ID");

    foreach (DataRow row in table.Rows)
    {
        Console.WriteLine(row["ID"]);
    }

    Console.WriteLine("Get Datatabe paging successfuly.");

    List<User> list = dao.GetListPaging(cmdText, 2, 10, "ORDER BY ID");
    foreach (User m in list)
    {
        Console.WriteLine(m.ID);
    }

    Console.WriteLine("Get Model list paging successfully.");

    cmdText = "DELETE FROM TUser";
    dao.ExecuteNonQuery(CommandType.Text, cmdText);
}

4  总结

这个版本的ORM示例,示例是没有认真去写了,因为不认为会有人用。但是这个ORM的代码是我认为比较简单的一个版本,只具有ORM的核心功能,几个类,只要具有c#基础的人都能看懂,有兴趣的可以看下。后续,自己会加上分页的Pager相关的内容、数据同步、数据验证的功能和和根据SQL自动生成实体对象的功能。

所有的源代码: BaseProject.7z

一个ORM的实现(附源代码),布布扣,bubuko.com

时间: 2024-11-05 15:58:29

一个ORM的实现(附源代码)的相关文章

挂钩SSDT详解附源代码

源代码下载地址:挂钩SSDT源代码 据微软所言,服务描述符表是一个由四个结构组成的数组,其中的每一个结构都是由四个双字项组成.因此,我们可以将服务描述符表表示为: typedef struct ServiceDescriptorTable { SDE ServiceDescriptor[4]; }SDT; 其中,其中的每一个服务描述符呈现出四个双字的形式,它的结构为: #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned

在Android中调用C#写的WebService(附源代码)

由于项目中要使用Android调用C#写的WebService,于是便有了这篇文章.在学习的过程中,发现在C#中直接调用WebService方便得多,直接添加一个引用,便可以直接使用将WebService当做一个对象使用,利用Vs2010中的代码提示功能就能爽歪歪地把想要的东西全部点出来.在Android调用,麻烦了一点,但是也还好.主要是我们需要自己在代码中确定要调用WebService的方法名是什么,要传给WebService什么参数以及对应的参数名,另外,一些额外的信息比如soap的版本号

效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】) 转

效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中[附源代码下载])  本文目录: (一)背景 (二)数据库数据导入到Excel的方法比较   (三)SSIS的简介   (四)数据库中存储过程示例(SSIS应用需要) (五)Excel模板的制作(这步这么简单,稍微介绍一下)   (六)SSIS操作过程(生成Package,用来调用)(下一篇随笔将详细讲解制作Package包的过程,图片太多,篇幅过长,因此本文将直接采用生成的Package包进行

仿酷狗音乐播放器开发日志二十一 开发动态调色板控件(附源代码)

转载请说明原出处,谢谢~~ 上一篇仿酷狗日志结束后,整个换肤功能就仅仅剩下调色板功能没有做了.我本以为会非常easy.可是研究了酷狗的调色板功能后发现不是那么简单的事情.首先看一下酷狗的调色板的样子: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1aG9uZ3NodQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > waterm

【COCOS2D-HTML5 开发之三】演示样例项目附源代码及执行的GIF效果图

本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/cocos2d-html5/1528.html ? 点击订阅 ? 本博客最新动态!及时将最新博文通知您! Cocos2dx html5开发,对于用过2d Or -x的童鞋来说非常easy,Himi这里也没有必要去再跟同学们具体的教学一遍. 所以Himi简单做了一个项目,供给大家參考,源代码下载地址及GIF截图在文章

Java设计模式-代理模式之动态代理(附源代码分析)

Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代理是在编译的时候就确定了代理类详细类型.假设有多个类须要代理.那么就得创建多个. 另一点,假设Subject中新增了一个方法,那么相应的实现接口的类中也要相应的实现这些方法. 动态代理的做法:在执行时刻.能够动态创建出一个实现了多个接口的代理类.每一个代理类的对象都会关联一个表示内部处理逻辑的Inv

VBS控制鼠标移动和点击(附源代码下载)

森思:想用vbs来控制鼠标的移动和点击,虽然按键精灵可以做到,但做这么简单的事情不想启动那么大一个程序,所以自己用VC写了一个小程序,可以让VBS来控制鼠标移动和点击. 用法: 移动鼠标到桌面坐标200,50的vbs命令如下: CreateObject("WScript.Shell").Run "mouse.exe m,200,50" 点击鼠标左键的vbs命令如下: CreateObject("WScript.Shell").Run "

【转】P2P之UDP穿透NAT的原理与实现(附源代码)

作者:shootingstars (有容乃大,无欲则刚)  日期:2004-5-25 出处:P2P中国(PPcn.net) P2P 之 UDP穿透NAT的原理与实现(附源代码)原创:shootingstars参考:http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt 论坛上经常有对P2P原理的讨论,但是讨论归讨论,很少有实质的东西产生(源代码).呵呵,在这里我就用自己实现的一个源代码来说明UDP穿越NAT的原理. 首先先介绍

AES加密算法(C++实现,附源代码)

先搞定AES算法,基本变换包含SubBytes(字节替代).ShiftRows(行移位).MixColumns(列混淆).AddRoundKey(轮密钥加) 其算法一般描写叙述为 明文及密钥的组织排列方式 ByteSubstitution(字节替代) 非线性的字节替代,单独处理每一个字节: 求该字节在有限域GF(28)上的乘法逆,"0"被映射为自身,即对于α∈GF(28),求β∈GF(28), 使得α·β=β·α=1mod(x8+x4+x2+x+1). 对上一步求得的乘法逆作仿射变换