本文手把手实现一个简单的ORM框架,仅作为学习,免去多余的功能,力求简单。本文使用VS2022,数据库是MS SQL Server。
一、 什么是ORM?
ORM即对象关系映射,英文叫:Object-Relational Mapping。它的作用是在将关系型数据库中的数据表和业务实体类之间作一个映射。ORM使得我们只需操作对象的方法和属性,即可完成对数据库的增删查改,避免了与复杂繁琐的SQL语句打交道。
ORM隐藏了访问数据库的细节,使得新手可以简单地操作数据库,但同时有些好学的技术人员希望了解ORM到底是怎么实现的。
二、ORM实现原理
我们都知道,操作数据库需要编写SQL语句,SQL语句有增删查改事务存储过程等。SQL语句都有固定的要求格式,而语句中的字段则是根据数据表字段的不同而不同。
(1)定义一个类,此类的属性与数据表的字段一一对应。
(2)利用C#中的反射,获得类的字段名称,类名等信息。
(3)当要向数据库新增数据时,将字段名、类名组装成SQL语句,再连接数据库进行执行,其他删除、查询、修改的操作也类似。
三、准备工作-创建数据表scheduleList
本实例使用VS2022,基于NET6,microsoft SQL Server 2012。新建一数据库,名称随意,并新建一数据表,名称scheduleList。有三个字段ID、title、和createTime,分别表示是主键ID,标题和创建时间。
四、定义scheduleList类
定义一个类,名为scheduleList。代码如下:
/**
*scheduleList.cs
*
*Ver 变更日期 作者
*V1.0 2022-03-28 12:33:21
*
*VX:lwdred QQ:463183376
*/
using System;
namespace Model.schedule
{
/// <summary>
///
/// </summary>
//[Serializable]
[EntityHelper.Model.Property("scheduleList")]
public class scheduleList
{
private long _id=0;
/// <summary>
/// ID
/// </summary>
[EntityHelper.Model.Property(EntityHelper.Model.ColumnKeyType.Identity)]
public long id
{
set{ _id=value;}
get{return _id;}
}
private string _title=string.Empty;
/// <summary>
/// 标题
/// </summary>
public string title
{
set{ _title=value;}
get{return _title;}
}
private DateTime _createtime=DateTime.Now;
/// <summary>
/// 创建时间
/// </summary>
public DateTime createTime
{
set{ _createtime=value;}
get{return _createtime;}
}
}
}
类scheduleList,有三个字段ID、title、和createTime,分别含义是主键ID,标题和创建时间。为简单起见,本ORM并没有作别名设计,所以注意三个字段名与数据库表中的字段需一摸一样。
其中以下语句是用来标记该字段ID作为主键。
[EntityHelper.Model.Property(EntityHelper.Model.ColumnKeyType.Identity)]
以下语句用来标记当前类对应的数据表名是:scheduleList。
[EntityHelper.Model.Property("scheduleList")]
五、通过反射从类信息中获得字段名称和数据表名称
//定义实体
scheduleList schedule = new scheduleList();
schedule.id= 1;
schedule.title = "标题";
schedule.createTime = DateTime.Now;
使用C#中的反射(System.Reflection),从实体中获得字段列表,将字段一一填充至SQL语句中,SQL语句就组装好了。
//通过反射获得实体字段
Type type = typeof(scheduleList);
PropertyInfo[] pis = type.GetProperties();
foreach (PropertyInfo pi in pis)
{
Console.WriteLine(pi.Name);
}
通过反射获得数据表的表名
PropertyAttribute property = (PropertyAttribute)(type.GetCustomAttributes(typeof(PropertyAttribute), false)[0]);
Console.WriteLine(property.tableName);
新增操作的完整代码:
#region 新增
/// <summary>
/// 新增
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="model">实体数据</param>
/// <param name="isIncludeKeyColumn">主键自增时:false、显式插入主键值:ture</param>
/// <param name="connString">连接字符串</param>
/// <returns></returns>
public bool Insert<T>(T model, bool isIncludeKeyColumn, string connString) where T : class
{
Type type = typeof(T);
if (type == null)
{
return false;
}
PropertyInfo[] pis = type.GetProperties();
if (pis == null || pis.Length <= 0)
{
return false;
}
//获取表名
string tableName = GetTableName(type);
if (string.IsNullOrEmpty(tableName))
{
return false;
}
List<string> columns = null;
if (isIncludeKeyColumn == false)
{
//主键自增
columns = GetTableColumnsList(pis, ColumnKeyType.Identity | ColumnKeyType.Extend|ColumnKeyType.WidthoutAdd);
}
else
{
//显式插入主键值
columns = GetTableColumnsList(pis, ColumnKeyType.Extend | ColumnKeyType.WidthoutAdd);
}
if (columns == null || columns.Count <= 0)
{
return false;
}
//生成INSERT语句
StringBuilder sqlText = new StringBuilder();
sqlText.Append("INSERT INTO ");
sqlText.Append(tableName);
sqlText.Append(" (");
for (int i = 0; i < columns.Count; i++)
{
sqlText.Append(columns[i]);
if (i < columns.Count - 1)
{
sqlText.Append(",");
}
}
sqlText.Append(") VALUES (");
for (int i = 0; i < columns.Count; i++)
{
sqlText.AppendFormat("@{0}", columns[i]);
if (i < columns.Count - 1)
{
sqlText.Append(",");
}
}
sqlText.Append(");");
SqlParameter[] paras = new SqlParameter[columns.Count];
for (int i = 0; i < paras.Length; i++)
{
PropertyInfo propertyInfo = type.GetProperty(columns[i]);
paras[i] = new SqlParameter(columns[i], GetMySqlDbType(propertyInfo.PropertyType), -1);
paras[i].Value = propertyInfo.GetValue(model, null);
}
return SqlHelper.ExecuteNonQuery(connString, sqlText.ToString(), paras);
}
#endregion
其它操作不再一一列出。
我已将代码上传,下载码是:4DACA2657F
下载码是啥?如何下载=》三味书屋-基于net6的简单ORM编码实现