Why hibernated does not create tables automatically?

zhmt via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Feb 12 19:19:08 PST 2015


finally ,I write a orm tool to replace hibernated, it is simple, 
and it is easy to use, and every thing in control.

It is free to copy ,improve.


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);
	}
}

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 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();
		CLS ret = new CLS;
		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;
			}
			__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;
	}
}



More information about the Digitalmars-d-learn mailing list