ORM框架可以根据数据库的表自动生成实体类,以及相应CRUD操作
本文是一个自动生成实体类的工具,用于生成Mysql表对应的实体类。
新建Winform窗体应用程序AutoGenerateForm,框架(.net framework 4.5),
添加对System.Configuration的引用,同时添加对SqlSugar.dll和MySql.Data.dll的引用。
SqlSugar是一种开源的ORM框架,可以直接在github上面下载。
将默认的Form1重命名为 FormGenerateClass。
一、在默认的App.config配置文件中配置MySql数据库连接
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="MySqlDataConnect" connectionString="server=127.0.0.1;Database=sh_db;Uid=root;Pwd=root" />
<add name="SqlServerDataConnect" connectionString="server=127.0.0.1;Database=ylq_db;Uid=root;Pwd=root" />
</connectionStrings>
</configuration>
二、新建文件操作类FileContentUtil.cs,源程序如下:
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AutoGenerateForm
{
/// <summary>
/// 写表名.cs实体类文件操作
/// </summary>
public class FileContentUtil
{
/// <summary>
/// Mysql列的数据类型 与 C#(CSharp)基础数据类型的映射表
/// 元组的第一项是MySql数据类型,元组的第二项是C#数据类型
/// </summary>
private static List<Tuple<string, string>> MappingTypesConst = new List<Tuple<string, string>>()
{
Tuple.Create("int","int"),
Tuple.Create("mediumint","int"),
Tuple.Create("integer","int"),
Tuple.Create("varchar","string"),
Tuple.Create("text","string"),
Tuple.Create("char","string"),
Tuple.Create("enum","string"),
Tuple.Create("mediumtext","string"),
Tuple.Create("tinytext","string"),
Tuple.Create("longtext","string"),
Tuple.Create("tinyint","byte"),
Tuple.Create("smallint","short"),
Tuple.Create("bigint","long"),
Tuple.Create("bit","bool"),
Tuple.Create("real","double"),
Tuple.Create("double","double"),
Tuple.Create("float","float"),
Tuple.Create("decimal","decimal"),
Tuple.Create("numeric","decimal"),
Tuple.Create("year","int"),
Tuple.Create("datetime","DateTime"),
Tuple.Create("timestamp","DateTime"),
Tuple.Create("date","DateTime"),
Tuple.Create("time","DateTime"),
Tuple.Create("blob","byte[]"),
Tuple.Create("longblob","byte[]"),
Tuple.Create("tinyblob","byte[]"),
Tuple.Create("varbinary","byte[]"),
Tuple.Create("binary","byte[]"),
Tuple.Create("multipoint","byte[]"),
Tuple.Create("geometry","byte[]"),
Tuple.Create("multilinestring","byte[]"),
Tuple.Create("polygon","byte[]"),
Tuple.Create("mediumblob","byte[]"),
//Tuple.Create("varchar","Guid"),
};
/// <summary>
/// 获取C#的数据类型字符串
/// 如果列是值类型,并且允许空,则需要在类型后加一个问号,如int?
/// 如果列是引用类型,或者【值类型 并且 不为空】,则类型后面不加问号,如 string
/// </summary>
/// <param name="dataType"></param>
/// <param name="IsNullable"></param>
/// <returns></returns>
private static string GetDataTypeString(string dataType, string isNullable)
{
string result = "object";
Tuple<string, string> keyValue = MappingTypesConst.Find(tuple => tuple.Item1 == dataType.ToLower());
if (keyValue != null)
{
result = keyValue.Item2;
}
//如果是值类型 并且 允许空。则为 可空值类型,类型后面加个?。如int? 就是 Nullable<int>
if (result != "string" && result != "byte[]" && result != "object" && isNullable == "1")
{
result += "?";
}
return result;
}
/// <summary>
/// 获取tableName.cs文件的全部内容文本
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="tableComment">表的注释说明</param>
/// <param name="dataTable">表的所有列信息:类型、列名、列的注释说明</param>
/// <returns></returns>
public static string GetFileContent(string tableName, string tableComment, DataTable dataTable)
{
string namespaceString = @"using System;
using System.Linq;
using System.Text;
namespace AutoGenerateForm.Models
{";
string classString = $@"
///<summary>
/// {tableComment}
///</summary>
public class {tableName}
{
{
";
StringBuilder sb = new StringBuilder(namespaceString);
sb.Append(classString);
for (int i = 0; i < dataTable.Rows.Count; i++)
{
string dataType = dataTable.Rows[i]["DataType"].ToString();
string columnName = dataTable.Rows[i]["DbColumnName"].ToString();
string columnComment = dataTable.Rows[i]["ColumnComment"].ToString();
string isNullable = dataTable.Rows[i]["IsNullable"].ToString();
string isPrimaryKey = dataTable.Rows[i]["IsPrimaryKey"].ToString();
dataType = GetDataTypeString(dataType, isNullable);
if (string.IsNullOrEmpty(columnComment))
{
//如果列的注释为空,则使用列名作为注释
columnComment = columnName;
}
//是否条码列
bool isBarcodeField = columnName.IndexOf("PackBarcode", StringComparison.CurrentCultureIgnoreCase) >= 0;
string attributeMessage = "";
if (isPrimaryKey == "1")
{
//如果是主键,增加特性 【主键】
attributeMessage = Environment.NewLine + " [SqlSugar.SugarColumn(IsPrimaryKey = true)]";
}
else if (isBarcodeField)
{
//如果是条码列,增加特性 【列描述是Barcode】
attributeMessage = Environment.NewLine + " [SqlSugar.SugarColumn(ColumnDescription = \"Barcode\")]";
}
sb.AppendLine($@" /// <summary>
/// {columnComment}
/// </summary>{attributeMessage}
public {dataType} {columnName} {
{ get; set; }}");
}
//增加类和命名空间的结束右大括号
sb.Append(@" }
}");
return sb.ToString();
}
/// <summary>
/// 创建一个文件,并将字符串写入文件。
/// </summary>
/// <param name="filePath">文件的绝对路径</param>
/// <param name="text">字符串数据</param>
/// <param name="encoding">字符编码</param>
public static void CreateFile(string filePath, string text, Encoding encoding)
{
try
{
if (File.Exists(filePath))
{
File.Delete(filePath);
}
//如果文件不存在则创建该文件
if (!File.Exists(filePath))
{
//实例化文件
FileInfo file = new FileInfo(filePath);
//获取文件目录路径
string fileDirectory = file.DirectoryName;
//如果文件的目录不存在,则创建目录
if (!Directory.Exists(fileDirectory))
{
Directory.CreateDirectory(fileDirectory);
}
//创建文件
using (FileStream stream = file.Create())
{
using (StreamWriter writer = new StreamWriter(stream, encoding))
{
//写入字符串
writer.Write(text);
//输出
writer.Flush();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"创建文件出现异常:{ex.Message}");
}
}
}
}
三、使用SqlSugar操作MySql的两个相关类 SugarDao.cs用于数据库连接,源程序:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using SqlSugar;
namespace AutoGenerateForm
{
/// <summary>
/// SqlSugar
/// </summary>
public class SugarDao
{
//禁止实例化
private SugarDao()
{
}
/// <summary>
/// 需添加对System.Configuration的引用
/// </summary>
/// <param name="index">1为Mysql连接 2为SqlServer连接</param>
/// <returns></returns>
public static string ConnectionString(int index = 1)
{
string reval = "server=localhost;Database=eve_db;Uid=root;Pwd=12345"; //这里可以动态根据cookies或session实现多库切换
if (index == 1)
reval = System.Configuration.ConfigurationManager.ConnectionStrings["MySqlDataConnect"].ConnectionString;//连接字符串
else if (index == 2)
reval = System.Configuration.ConfigurationManager.ConnectionStrings["SqlServerDataConnect"].ConnectionString;//连接字符串
return reval;
}
public static SqlSugarClient GetInstance(SqlSugar.DbType dbType = SqlSugar.DbType.MySql, int index = 1)
{
return new SqlSugarClient(new ConnectionConfig()
{
DbType = dbType,
ConnectionString = ConnectionString(index),
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true,
AopEvents = new AopEvents
{
OnLogExecuting = (sql, p) =>
{
Console.WriteLine(sql);
Console.WriteLine(string.Join(",", p?.Select(it => it.ParameterName + ":" + it.Value)));
}
}
});
}
/// <summary>
/// 检查数据库连接
/// </summary>
public static void CheckConnect()
{
var db = GetInstance();
db.Open();
}
}
}
四、第二个类RawSql.cs,用于执行sql相关操作,源程序
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AutoGenerateForm
{
/// <summary>
/// 原生的sql增删改查
/// </summary>
public class RawSql
{
/// <summary>
/// 执行原生的Sql与sql参数的insert、update、delete等操作,返回受影响的行数
/// </summary>
/// <param name="sql"></param>
/// <param name="dict"></param>
/// <param name="dbType">数据库类型,一般是mysql</param>
/// <param name="index">额外的连接数据库,2为新的数据库连接字符串</param>
/// <returns></returns>
public static int ExecuteCommand(string sql, Dictionary<string, object> dict, SqlSugar.DbType dbType = SqlSugar.DbType.MySql, int index = 1)
{
List<SugarParameter> parameters = DictToList(dict);
using (var db = SugarDao.GetInstance(dbType, index))
{
return db.Ado.ExecuteCommand(sql, parameters);
}
}
/// <summary>
/// 执行原生的Sql与sql参数的select查询等操作,返回首行首列的数据
/// </summary>
/// <param name="sql"></param>
/// <param name="dict"></param>
/// <param name="dbType">数据库类型,一般是mysql</param>
/// <param name="index">额外的连接数据库,2为新的数据库连接字符串</param>
/// <returns></returns>
public static object GetScalar(string sql, Dictionary<string, object> dict, SqlSugar.DbType dbType = SqlSugar.DbType.MySql, int index = 1)
{
List<SugarParameter> parameters = DictToList(dict);
using (var db = SugarDao.GetInstance(dbType, index))
{
return db.Ado.GetScalar(sql, parameters);
}
}
/// <summary>
/// 执行原生的Sql与sql参数的select查询等操作,返回一个数据表
/// </summary>
/// <param name="sql"></param>
/// <param name="dict"></param>
/// <param name="dbType">数据库类型,一般是mysql</param>
/// <param name="index">额外的连接数据库,2为新的数据库连接字符串</param>
/// <returns></returns>
public static DataTable GetDataTable(string sql, Dictionary<string, object> dict, SqlSugar.DbType dbType = SqlSugar.DbType.MySql, int index = 1)
{
List<SugarParameter> parameters = DictToList(dict);
using (var db = SugarDao.GetInstance(dbType, index))
{
return db.Ado.GetDataTable(sql, parameters);
}
}
/// <summary>
/// 字典转参数列表
/// </summary>
/// <param name="dict"></param>
/// <returns></returns>
private static List<SugarParameter> DictToList(Dictionary<string, object> dict)
{
List<SugarParameter> parameters = new List<SugarParameter>();
for (int i = 0; dict != null && i < dict.Count; i++)
{
KeyValuePair<string, object> keyValuePair = dict.ElementAt(i);
parameters.Add(new SugarParameter(keyValuePair.Key, keyValuePair.Value));
}
return parameters;
}
}
}
五、窗体FormGenerateClass.cs 设计如下:
窗体的FormGenerateClass.cs主要代码如下(忽略设计器自动生成的代码):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AutoGenerateForm
{
public partial class FormGenerateClass : Form
{
public FormGenerateClass()
{
InitializeComponent();
}
private void btnGenerate_Click(object sender, EventArgs e)
{
rtxbClassContent.Clear();
if (cboTable.SelectedIndex == -1)
{
cboTable.Focus();
DisplayInfo("没有选择相应的表名,请检查...");
return;
}
string tableName = Convert.ToString(cboTable.SelectedValue);
string tableComment = cboTable.Text;
DisplayInfo($"已选择表【{tableName}】,准备自动生成实体类...");
string sql = $@"SELECT TABLE_NAME as TableName,
column_name AS DbColumnName,
CASE WHEN left(COLUMN_TYPE,LOCATE('(',COLUMN_TYPE)-1)='' THEN COLUMN_TYPE ELSE left(COLUMN_TYPE,LOCATE('(',COLUMN_TYPE)-1) END AS DataType,
CAST(SUBSTRING(COLUMN_TYPE,LOCATE('(',COLUMN_TYPE)+1,LOCATE(')',COLUMN_TYPE)-LOCATE('(',COLUMN_TYPE)-1) AS signed) AS Length,
column_default AS `DefaultValue`,
column_comment AS `ColumnComment`,
CASE WHEN COLUMN_KEY = 'PRI' THEN true ELSE false END AS `IsPrimaryKey`,
CASE WHEN EXTRA='auto_increment' THEN true ELSE false END as IsIdentity,
CASE WHEN is_nullable = 'YES' THEN true ELSE false END AS `IsNullable`
FROM Information_schema.columns where TABLE_NAME='{tableName}' and TABLE_SCHEMA=(select database()) ORDER BY TABLE_NAME";
DataTable dataTable = RawSql.GetDataTable(sql, null);
if (dataTable == null || dataTable.Rows.Count == 0)
{
DisplayInfo($"没有找到表【{tableName}】的字段(列)信息...");
return;
}
string fileDirectory = AppDomain.CurrentDomain.BaseDirectory + @"AutoGenerateCodes\Models";//生成到的路径
string filePath = $"{Path.Combine(fileDirectory, tableName)}.cs";
string text = FileContentUtil.GetFileContent(tableName, tableComment, dataTable);
FileContentUtil.CreateFile(filePath, text, Encoding.UTF8);
DisplayInfo($"自动生成实体类【{tableName}】成功.实体类路径:{filePath}");
rtxbClassContent.AppendText(text);
}
private void FormGenerateClass_Load(object sender, EventArgs e)
{
string sqlAllTables = "SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE,CREATE_TIME,TABLE_COMMENT FROM information_schema.`TABLES` where TABLE_SCHEMA = (select database())";
DataTable dataTable = RawSql.GetDataTable(sqlAllTables, null);
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = dataTable;
cboTable.DataSource = bindingSource;
cboTable.ValueMember = "TABLE_NAME";
cboTable.DisplayMember = "TABLE_COMMENT";
}
/// <summary>
/// 显示文本框的消息
/// </summary>
/// <param name="message"></param>
private void DisplayInfo(string message)
{
this.BeginInvoke(new Action(() =>
{
if (rtxbResult.TextLength >= 20480)
{
rtxbResult.Clear();
}
rtxbResult.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} --> {message}\n");
rtxbResult.ScrollToCaret();
}));
}
}
}