原本orm使用的hibernated,不知什么原因,一个周后,代码突然不能正常运行,自己查了半天,没解决。到dlang官方论坛,以及hibernated的官方,都没找到解决办法。无奈只能退回到使用mysql的客户端。

但是现在处于开发初期,表结构的改变非常频繁,每次修改类、数据库,sql语句,想想都觉得太麻烦,自动动手,写了一个简单的orm工具;现在只支持从类生成表,修改类定义后自动修改表定义。代码如下,欢迎复制、改进:

支持的功能:

表的自动创建,

列的添加、删除,

索引的创建、修改,

指定某列是否为null

module mysqlormutil;

import vibe.d;
import std.stdio;

import mysql.connection;
import mysql.db;

struct NotNull
{
}

struct Auto
{
}

struct Index
{
    string name;
    string [] cols;
}

struct UniqueIndex
{
    string name;
    string[] cols;
}

class TableIndexInfo
{
    public string indexName;
    public string[] cols;
    public bool isUnique;
}

class MysqlOrmUtil
{
    //更新表结构
    public static void updateTableSchema(CLS)(Connection conn)
    {
        MysqlOrmInternalUtil.updateTableSchema!(CLS)(conn);
    }
    
    //生成replace语句,保存整个对象
    public static string genSaveAllSql(CLS)(ref CLS obj)
    {
        return MysqlOrmInternalUtil.genSaveAllSql!(CLS)(obj);
    }
    
    public static string genInsertSqlWithoutId(CLS)(string idColName,ref CLS obj)
    {
        return MysqlOrmInternalUtil.genInsertSqlWithoutId!(CLS)(idColName,obj);
    }

public static ulong exeSql(string sql,Connection conn)
    {
        return MysqlOrmInternalUtil.exeSql(sql,conn);
    }

public static CLS exeQueryToObj(CLS)(string sql,Connection conn)
    {
        return MysqlOrmInternalUtil.exeQueryToObj!(CLS)(sql,conn);
    }
    
    public static CLS exeQueryToStruct(CLS)(string sql,Connection conn)
    {
        return MysqlOrmInternalUtil.exeQueryToStruct!(CLS)(sql,conn);
    }

public static CLS[] exeQueryToObjArr(CLS)(string sql,Connection conn)
    {
        return MysqlOrmInternalUtil.exeQueryToObjArr!(CLS)(sql,conn);
    }
    
    public static CLS[] exeQueryToStructArr(CLS)(string sql,Connection conn)
    {
        return MysqlOrmInternalUtil.exeQueryToStructArr!(CLS)(sql,conn);
    }

public static string toString(CLS)(CLS obj)
    {
        return MysqlOrmInternalUtil.toString(obj);
    }
}

class MysqlOrmInternalUtil
{
    __gshared static string[string] dToMysql ;
    shared static this()
    {
        dToMysql["int"] = "int";
        dToMysql["long"] = "bigint(20)";
        dToMysql["string"] = "varchar(128)";
        dToMysql["bool"] = "tinyint(1)";
    }
    
    public static string getMysqlType(string dtype)
    {
        return dToMysql[dtype];
    }

public static string toString(CLS)(CLS obj)
    {
        if(obj is null) 
        {
            return null;
        }

string ret;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;
            ret ~= name ~ ":" ~ to!string(__traits(getMember, obj, name)) ~ ",";
        }
        return ret;
    }

public static CLS[] exeQueryToObjArr(CLS)(string sql,Connection conn)
    {
        Command cmd =  Command(conn);
        cmd.sql = sql;
        ResultSet  rs = cmd.execSQLResult();
        CLS[] ret = resultSetToObjArray!(CLS)(rs);
        return ret;
    }
    
    public static CLS[] exeQueryToStructArr(CLS)(string sql,Connection conn)
    {
        Command cmd =  Command(conn);
        cmd.sql = sql;
        ResultSet  rs = cmd.execSQLResult();
        CLS[] ret = resultSetToStructArray(rs);
        return ret;
    }

public static CLS exeQueryToObj(CLS)(string sql,Connection conn)
    {
        Command cmd =  Command(conn);
        cmd.sql = sql;
        ResultSet  rs = cmd.execSQLResult();
        if(rs.length==0)
        {
            return null;
        }
        CLS ret = resultSetToObj!(CLS)(rs);
        return ret;
    }

public static CLS exeQueryToStruct(CLS)(string sql,Connection conn)
    {
        Command cmd = new Command(conn);
        cmd.sql = sql;
        ResultSet  rs = cmd.execSQLResult();
        CLS ret;
        resultSetToStruct!(CLS)(rs);
        return ret;
    }

public static ulong exeSql(string sql,Connection conn)
    {
        Command cmd =  Command(conn);
        cmd.sql = sql;
        ulong ret;
        cmd.execSQL(ret);
        return ret;
    }
    
    public static CLS[] resultSetToObjArray(CLS)(ref ResultSet rs)
    {
        CLS[] arr;
        foreach(Row row ; rs)
        {
            CLS obj = new CLS;
            rowToObjOrStruct!(CLS)(rs,row,obj);
            arr ~= obj;
        }
        return arr;
    }
    
    public static CLS resultSetToObj(CLS)(ref ResultSet rs)
    {
        if(rs.length == 0)  
        {
            return null;
        }
        
        CLS ret = new CLS;
        resultSetToObjOrStruct!(CLS)(rs,ret);
        return ret;
    }
    
    public static CLS[] resultSetToStructArray(CLS)(ref ResultSet rs)
    {
        CLS[] arr;
        foreach(Row row ; rs)
        {
            CLS obj;
            rowToObjOrStruct(row,obj);
            arr ~= obj;
        }
        return arr;
    }
    
    public static CLS resultSetToStruct(CLS)(ref ResultSet rs)
    {
        if(rs is null || rs.length ==0)  
        {
            return null;
        }
        
        CLS ret;
        resultSetToObjOrStruct(rs,obj);
        return ret;
    }
    
    public  static void resultSetToObjOrStruct(CLS)(ref ResultSet rs,ref CLS obj)
    {
        foreach(Row row ; rs)
        {
            rowToObjOrStruct!(CLS)(rs,row,obj);
            break;
        }
    }
    
    public static void rowToObjOrStruct(CLS)(ref ResultSet rs,Row row ,ref CLS obj)
    {
        ulong overflow = 1000000;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;

ulong index = rs.colNameIndicies.get(name,overflow);
            if(index == overflow)
            {
                continue;
            }

static if (is(typeof(__traits(getMember, obj, name)) == bool))
            {
                long tmp = row[index].get!(long);
                __traits(getMember, obj, name) = (tmp!=0);
            } else 
            {
                __traits(getMember, obj, name) = row[index].get!(type) ;
            }

}
    }
    
    //更新表结构
    public static void updateTableSchema(CLS)(Connection conn)
    {
        string tableName = CLS.stringof;
        string[string] old =getTableTypes(conn,tableName);
        string[string] newsch = getClsMysqlTypes!(CLS)();
        string[] sqls = genTableFieldsUpdateSql(tableName,old,newsch);
        auto cmd = Command(conn);
        ulong rowsAffected;
        //更新表的列
        foreach(s ; sqls)
        {
            cmd.sql = s;
            writeln(s);
            cmd.execSQL(rowsAffected);
            writeln(std.string.format("affected : %s",rowsAffected));
        }
        
        //更新索引
        TableIndexInfo[string] newindices = getClsIndexInfo!(CLS)();
        TableIndexInfo[string] oldindices = getTableIndexInfo!(CLS)(conn);
        sqls = genIndexUpdateSql!(CLS)(conn,newindices,oldindices);
        foreach(s ; sqls)
        {
            cmd.sql = s;
            writeln(s);
            try{
                cmd.execSQL(rowsAffected);
                writeln(std.string.format("affected : %s",rowsAffected));
            }catch(Exception e) 
            {
                writeln(e.msg);
            }
        }
        //更新列的额外限制
        sqls = genFieldConstraintSql!(CLS)(conn);
        foreach(s ; sqls)
        {
            cmd.sql = s;
            writeln(s);
            try{
                cmd.execSQL(rowsAffected);
                writeln(std.string.format("affected : %s",rowsAffected));
            }catch(Exception e)
            {
                writeln(e);
            }
        }
    }
    
    public static string genSaveAllSql(CLS)(ref CLS obj)
    {
        string[] arr;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;
            auto v = __traits(getMember,obj,name);
            if(typeid(type)==typeid(string))
            {
                arr ~= std.string.format("%s='%s'",name,v);
            }else
            {
                arr ~= std.string.format("%s=%s",name,v);
            }
        }
        string sql = std.string.format("replace %s set %s",CLS.stringof,arr.join(","));
        return sql;
    }
    
    public static string genInsertSqlWithoutId(CLS)(string idColName,ref CLS obj)
    {
        string[] arr;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;
            if(idColName == name)
            {
                continue;
            }
            auto v = __traits(getMember,obj,name);
            if(typeid(type)==typeid(string))
            {
                arr ~= std.string.format("%s='%s'",name,v);
            }else
            {
                arr ~= std.string.format("%s=%s",name,v);
            }
        }
        string sql = std.string.format("insert into %s set %s",CLS.stringof,arr.join(","));
        return sql;
    }
    
    //拼接索引sql语句
    public static string[] genIndexUpdateSql(CLS)(Connection conn,TableIndexInfo[string] newinfo,TableIndexInfo[string] old)
    {
        string[] arr;
        
        //find indices to be deleted.
        foreach(TableIndexInfo v; old.values)
        {
            if(newinfo.get(v.indexName,null) is null)
            {
                string sql =  std.string.format( "alter table %s drop INDEX %s",CLS.stringof,v.indexName);
                arr ~= sql;
            }
        }
        
        //find indices to be modified.
        foreach(TableIndexInfo v; newinfo.values)
        {
            TableIndexInfo oldOne = old.get(v.indexName,null);
            bool createNew = false;
            bool dropOld = false;
            if(oldOne is null)
            {
                createNew = true;
            }else if(oldOne.isUnique==v.isUnique && oldOne.cols==v.cols){
                //same;
            } else {
                createNew = true;
                dropOld = true;
            }
            
            if(dropOld) 
            {
                string sql =  std.string.format( "alter table %s drop INDEX %s",CLS.stringof,v.indexName);
                arr ~= sql;
            }
            
            if(createNew)
            {
                if(v.isUnique)
                {
                    string sql = std.string.format( "alter table %s add UNIQUE %s (%s)",CLS.stringof,v.indexName,v.cols.join(","));
                    arr ~= sql;
                }else
                {
                    string sql = std.string.format( "alter table %s add INDEX %s (%s)",CLS.stringof,v.indexName,v.cols.join(","));
                    arr ~= sql;
                }
            }
        }
        
        
        return arr;
    }
    
    //获取类索引信息
    public static TableIndexInfo[string] getClsIndexInfo(CLS)() 
    {
        TableIndexInfo[string] arr;
        
        auto all = __traits(getAttributes, CLS);
        foreach(one ; all)
        {
            if(typeid(one)==typeid(Index)) 
            {
                Index index = cast(Index)(one);
                TableIndexInfo info = new TableIndexInfo;
                info.indexName = index.name;
                info.cols = index.cols;
                info.isUnique = false;
                
                arr[info.indexName] = info;
            }else if(typeid(one)==typeid(UniqueIndex))
            {
                UniqueIndex index = cast(UniqueIndex)(one);
                
                TableIndexInfo info = new TableIndexInfo;
                info.indexName = index.name;
                info.cols = index.cols;
                info.isUnique = true;
                
                arr[info.indexName] = info;
            }
        }
        return arr;
    }
    
    
    
    //获取索引信息
    public static TableIndexInfo[string] getTableIndexInfo(CLS)(Connection conn)
    {
        TableIndexInfo[string] arr;
        auto cmd = new Command(conn);
        cmd.sql = std.string.format("show index from %s",CLS.stringof);
        
        ResultSet rs = cmd.execSQLResult();
        if(rs.length==0)
        {
            return arr;
        }
        
        foreach(Row row ; rs)
        {
            string keyName = row[rs.colNameIndicies["Key_name"]]._toString();
            string colName = row[rs.colNameIndicies["Column_name"]]._toString();
            long isUnique = row[rs.colNameIndicies["Non_unique"]].get!(long);
            
            TableIndexInfo info = arr.get(keyName,null);
            if(info is null)
            {
                info = new TableIndexInfo;
                arr[keyName] = info;
            }
            
            info.indexName = keyName;
            info.cols ~= colName;
            info.isUnique = (isUnique==0);
        }
        return arr;
    }
    
    //生成列限制sql
    public static string[] genFieldConstraintSql(CLS)(Connection conn)
    {
        MetaData md = MetaData(conn);
        
        ColumnInfo[] ca = md.columns(CLS.stringof);
        bool[string] nullmap;
        
        foreach( one ; ca)
        {
            nullmap[one.name] = one.nullable;
        }
        
        string[] arr;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;
            //string typestring = type.stringof;
            auto all = __traits(getAttributes, CLS.tupleof[i]);
            string[] cons;
            bool nullable = true;
            foreach(att ; all)
            {
                if(typeid(att) == typeid(Auto)) 
                {
                    cons ~= "AUTO_INCREMENT";
                } else if(typeid(att) == typeid(NotNull))
                {
                    nullable = false;
                }
            }
            
            if(cons.length>0) 
            {
                //如果修改别的属性,null属性必须带
                cons ~= nullable?"NULL" : "NOT NULL";
            }else
            {
                //如果不修改别的属性,检测null属性是否需要修改
                if(nullable && !nullmap[name]) 
                {
                    cons ~= "NULL";
                }else if(!nullable && nullmap[name]) 
                {
                    cons ~= "NOT NULL";
                }
            }
            
            if(cons.length>0)
            {
                string sql = std.string.format("alter table %s change %s %s %s %s",CLS.stringof,name,name,getMysqlType(type.stringof),cons.join(" "));
                arr ~= sql;
            }
        }
        return arr;
    }
    
    //获取类的所有字段对应的mysql类型
    public static string[string] getClsMysqlTypes(CLS)()
    {
        string[string] arr;
        foreach (i, type; typeof(CLS.tupleof)) 
        {
            enum name =  CLS.tupleof[i].stringof;
            string typestring = type.stringof;
            arr[name] = getMysqlType(typestring);
        }
        return arr;
    }
    
    //从数据库中获取表字段的类型   
    public static string[string] getTableTypes(Connection conn,string table)
    {
        string[string] arr;
        MetaData md = MetaData(conn);
        
        ColumnInfo[] ca = md.columns(table);
        foreach(info ; ca)
        {
            arr[info.name] = info.colType;
        }
        
        return arr;
    }
    
    //生成字段修改sql
    public static string[] genTableFieldsUpdateSql(string tableName,string[string] old,string[string] newtab)
    {
        string[] arr;
        if(old is null || old.length==0)
        {
            arr ~= genTableCreateSql(tableName,newtab);
            return arr;
        }
        
        //check column updates
        foreach(name;newtab.keys())
        {
            string oldType = old.get(name,null);
            string newType = newtab[name];
            
            if(oldType is null)
            {
                //add column;
                string sql = std.string.format("alter table %s add %s %s",tableName,name,newType);
                arr ~= sql;
            }else if(oldType == newType) 
            {
                // same definition
            }else 
            {
                //alter table
                string sql = std.string.format("alter table %s change %s %s %s",tableName,name,name,newType);
                arr ~= sql;
            }
        }
        
        //check columns to delete
        foreach(name; old.keys())
        {
            string newtype = newtab.get(name,null);
            if(newtype is null)
            {
                string sql = std.string.format("alter table %s drop %s",tableName,name);
                arr ~= sql;
            }
        }
        
        return arr;
    }
    
    //生成创建表的sql
    public static string genTableCreateSql(string tableName,string[string] types)
    {
        string[] arr;
        foreach (name;types.keys()) {
            string typestring = types[name];
            arr ~= name~" "~typestring;
        }
        string sql = "create table " ~ tableName ~ "(";
        sql ~= arr.join(",");
        sql ~= ") ENGINE=InnoDB DEFAULT CHARSET=utf8";
        return sql;
    }
}

用法:

@UniqueIndex("id",["id"])
class Card
{
    @NotNull()
    @Auto()
    long id;
    string pwd;
    long agentId;
    bool valid;
    long rmb;
    long createDate;
    long soldDate;
    long chargeDate;
}

string connStr = "host=10.211.55.10;port=3306;user=root;pwd=xxx;db=test";
        mdb = new MysqlDB(connStr);

auto conn = mdb.lockConnection();
        scope(exit) conn.close();
        MysqlOrmUtil.updateTableSchema!(Customer)(conn);
        MysqlOrmUtil.updateTableSchema!(Card)(conn);
        MysqlOrmUtil.updateTableSchema!(Agent)(conn);

public void createCards(long agentId,long rmb,long count) 
    {
        long curTime = now();
        Connection conn = mdb.lockConnection();
        scope(exit) conn.close();

for(int i=0; i<count; i++)
        {
            Card card = new Card();
            card.agentId = agentId;
            card.createDate = curTime;
            card.pwd = createCardPwd();
            card.rmb = rmb;
            card.valid = true;
            string sql = MysqlOrmUtil.genInsertSqlWithoutId("id",card);
            MysqlOrmUtil.exeSql(sql,conn);
        }
    }

public Card getValidCardInfo(long cardId ,string cardPassword)
    {
        Connection conn = mdb.lockConnection();
        scope(exit) conn.close();
        string sql = std.string.format("select * from Card where cardId=%s and pwd='%s' and valid=%s",cardId,cardPassword,true);
        Card ret = MysqlOrmUtil.exeQueryToObj!(Card)(sql,conn);
        return ret;
    }

[dlang](4)自定义的mysql orm工具相关推荐

  1. Smart ORM v0.3发布(完全面向对象的轻量级ORM工具)

    1. Smart ORM .NET概述 Smart ORM .NET 是基于.NET 2.0的轻量级ORM工具.一般的ORM工具是通过建立数据表格,然后根据表格创建实体类型,而SmartORM则是通过 ...

  2. 介绍一个C++的ORM工具ODB(一) | C瓜哥的博客

    介绍一个C++的ORM工具ODB(一) | C瓜哥的博客 介绍一个C++的ORM工具ODB(一) 前段时间了解了下ORM(对象关系映射),然后就找了下C++的ORM框架,发现真的是很少,主要就下面几种 ...

  3. dba用什么工具连接mysql_DBA必备的15款MySQL管理工具

    原文:http://www.techxue.com/techxue-11898-1.html 如今,Web应用程序的响应速度是成功的关键法宝之一.它与用户互动,用户对网站的看法,甚至谷歌网站排名情况都 ...

  4. Spring - Java/J2EE Application Framework 应用框架 第 11 章 使用ORM工具进行数据访问

    第 11 章 使用ORM工具进行数据访问 11.1. 简介 Spring在资源管理,DAO实现支持以及实物策略等方面提供了与Hibernate, JDO和iBATIS SQL映射的集成. 对Hiber ...

  5. 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil

    基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...

  6. MySQL管理工具MySQL Utilities — 如何连接MySQL服务器

    连接参数 连接到一个服务器,必须指定连接参数,如用户名,主机名称,密码,端口号,socket.MySQL Utilities提供了三种提供这些参数的方法,这些方法都需要通过命令行指定. 使用.mylo ...

  7. MySQL管理工具HeidiSQL

    MySQL管理工具HeidiSQL HeidiSQL 是一个功能非常强大的 MySQL 客户端软件.它是德国程序员Ansgar Becker和几个Delphi程序员开发的一个开源工具.要通过Heidi ...

  8. 怎么用debug看jdbc查询的resultset中查出的数据_用了这个 ORM 工具,我只用一天就把项目数据库给换了

    背景 项目开发过程中,需要更换数据库,原来调研用的 NoSQL 型数据库,现在要换成 RDB 数据库.DAO 层抽象了一个顶层的父类,所以打算以此类着手重写一整套操作,可以将换库工作量降低到最少. 那 ...

  9. 云时代,最好用的MySQL客户端工具推荐

    数据库图形客户端(GUI)工具,可以大大帮助开发者提升SQL编写与开发的效率.在云时代,企业越来越多的开始采用RDS,同时也还有部分本地IDC自建数据库,而在云端也会选择/尝试多个不同云厂商.&quo ...

  10. 15款最佳的MySQL管理工具和应用程序

    [转]15款最佳的MySQL管理工具和应用程序@TOC 工欲善其事,必先利其器.几乎每个开发人员都有最钟爱的 MySQL 管理工具,它帮助开发人员在许多方面支持包括 PostgreSQL,MySQL, ...

最新文章

  1. 爬虫之selenium对cookie的处理
  2. 对HA的简单认识以及HA集群删除
  3. 第36-37 Tomcat SVN
  4. pcm 采样率转换_All Video Converter Pro for mac(音视频格式转换器)
  5. .NET Core开发实战(第26课:工程结构概览:定义应用分层及依赖关系)--学习笔记...
  6. python 天勤 金叉 编程代码_Python量化策略开发框架,固定的套路、突破策略的福音...
  7. 2018/06/30这段时间的随笔记忆:遇到概念模糊的js问题
  8. android textview显示表情,Android开发-TextView中显示QQ表情类的图片和超链接
  9. C++ stl库 手写 源码分析
  10. webservice接口对接
  11. 学编程一定要数学很好吗?看到网友这样说,我松了一口气 ...
  12. 唐太宗灵州受降【会盟】的意义
  13. 验证码爬取并识别-云大urp教务系统大作战(1)
  14. 二阶可导的充要条件_可导函数在x
  15. 统计笔记4:ANOVA
  16. ES6笔记(完整详细版)
  17. 【高级篇 / DNS】(7.0) ❀ 05. 用花生壳作 FortiGate 的 DDNS ❀ FortiGate 防火墙
  18. 数字基带传输系统无码间干扰的研究与仿真
  19. BiTraP:Bi-directional Pedestrian Trajectory Prediction with Multi-modal Goal Estimation
  20. 爱做梦的人-人的特性之一

热门文章

  1. 如何删除计算机新用户,如何将电脑里的账户信息彻底删除
  2. 数据分析学习总结笔记06:T检验的原理和步骤
  3. python 批量更改扩展名
  4. Python绘制折线图
  5. COOC+VOSviewer可取代任何文献计量与知识图谱软件
  6. 通过UEFI禁用 BD PROCHOT
  7. Vivado使用系列:使用自定义BD
  8. 网络编程——Java Email
  9. Mac连接Ubuntu服务器并用屏幕共享app显示远程应用图形界面
  10. heka 输出到mysql_Heka配置的详细介绍