手写ORM入门篇(一)
对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。
对象关系映射(Object-Relational Mapping)提供了概念性的、易于理解的模型化数据的方法。ORM方法论基于三个核心原则: 简单:以最基本的形式建模数据。 传达性:数据库结构被任何人都能理解的语言文档化。 精确性:基于数据模型创建正确标准化的结构。 典型地,建模者通过收集来自那些熟悉应用程序但不熟练的数据建模者的人的信息开发信息模型。建模者必须能够用非技术企业专家可以理解的术语在概念层次上与数据结构进行通讯。建模者也必须能以简单的单元分析信息,对样本数据进行处理。ORM专门被设计为改进这种联系。
简单的说:ORM相当于中继数据。具体到产品上,例如ADO.NET Entity Framework。DLINQ中实体类的属性[Table]就算是一种中继数据。
BaseModel示例代码:
public class BaseModel
{
/// <summary>
/// 所有实体的父类,非自增主键GUID
/// </summary>
public string Id { set; get; }
}
User示例代码:
public class User : BaseModel
{
public string Account { get; set; } public string Password { get; set; } public string Name { get; set; } public int Sex { get; set; } public int Status { get; set; } public string BizCode { get; set; } public DateTime CreateTime { get; set; } public string CrateId { get; set; } public string TypeName { get; set; } public string TypeId { get; set; } }
IBaseDAL示例代码:
public interface IBaseDAL
{
/// <summary>
/// 根据主键返回一个实体
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <returns></returns>
T Find<T>(string id) where T : BaseModel; /// <summary>
/// 返回一个List<Medel>实体集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
List<T> FindAll<T>() where T : BaseModel; /// <summary>
/// 添加一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
bool Add<T>(T t) where T : BaseModel; /// <summary>
/// 更新一个实体
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
bool Update<T>(T t) where T : BaseModel; /// <summary>
/// 删除一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
bool Delete<T>(T t) where T : BaseModel;
}
BaseDAL示例代码
/// <summary>
/// 泛型方法添加BaseModel约束,所有实体类必须有一个非自增的主键Id,Id的值为随机的GUID,
/// </summary>
public class BaseDAL : IBaseDAL
{
/// <summary>
/// 数据库连接字符串
/// </summary>
private static string ConnectionString = ConfigurationManager.ConnectionStrings["OpenAuthDB"].ConnectionString; public bool Add<T>(T t) where T : BaseModel
{
Type type = t.GetType();
string columnStr = string.Join(",", type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => $"[{p.Name}]"));
string valueStr = string.Join(",", type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => $"@{p.Name}"));
var parameterList = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => new SqlParameter($"@{p.Name}", p.GetValue(t) ?? DBNull.Value));
string sqlStr = $"Insert Into [{type.Name}] ({columnStr}) values ({valueStr})";
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(sqlStr, conn);
command.Parameters.AddRange(parameterList.ToArray());
conn.Open();
//如果Id是自增的,在sql后面增加个 Select @@Identity; command.ExecuteScalar,新增后把Id拿出来.
return command.ExecuteNonQuery() > ;
}
} public bool Delete<T>(T t) where T : BaseModel
{
//获取T的类型
Type type = typeof(T);
var parameter = new SqlParameter("Id", type.GetProperty("Id").GetValue(t) ?? DBNull.Value);
string strSql = $"DELETE FROM [{type.Name}] WHERE Id = @Id";
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(strSql, conn);
command.Parameters.Add(parameter);
conn.Open();
var iRes = command.ExecuteNonQuery();
return iRes > ? true : false;
}
} public List<T> FindAll<T>() where T : BaseModel
{
Type type = typeof(T);
string sqlStr = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}]";
List<T> list = new List<T>();
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(sqlStr, conn);
conn.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
list.Add(this.Trans<T>(type, reader));
}
}
return list;
} public T Find<T>(string id) where T : BaseModel
{
Type type = typeof(T);
string sql = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}] WHERE ID = '{id}' ";
object oObject = Activator.CreateInstance(type);
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(sql, conn);
conn.Open();
var reader = command.ExecuteReader();
if (reader.Read())
return this.Trans<T>(type, reader);
else
return default(T);
}
} public bool Update<T>(T t) where T : BaseModel
{
Type type = typeof(T);
StringBuilder sb = new StringBuilder();
sb.Append($"UPDATE [{type.Name}] SET ");
var propArray = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
var propArrayLen = propArray.Count();
for (int i = ; i < propArrayLen; i++)
{
var propertiesName = propArray[i].Name;
if (i != propArrayLen - )
sb.Append($"{propertiesName} = @{propertiesName}, ");
else
sb.Append($" {propertiesName} = @{propertiesName} ");
}
#region 使用foreach的写法
//foreach (var properties in propArray)
//{
// var propertiesName = properties.Name;
// if (i != propArrayLen)
// sb.Append($"{propertiesName} = @{propertiesName}, ");
// else
// sb.Append($" {propertiesName} = @{propertiesName} ");
// i++;
//}
#endregion
sb.Append($" Where Id = @Id;");
var parameterList = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => new SqlParameter($"@{p.Name}", p.GetValue(t) ?? DBNull.Value));
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(sb.ToString(), conn);
command.Parameters.AddRange(parameterList.ToArray());
conn.Open();
return command.ExecuteNonQuery() > ;
}
} #region Private Method
private T Trans<T>(Type type, SqlDataReader reader)
{
object oObject = Activator.CreateInstance(type);
foreach (var properties in type.GetProperties())
{
properties.SetValue(oObject, reader[properties.Name] ?? DBNull.Value);
}
return (T)oObject;
}
#endregion
}
方法调用示例代码:
static void Main(string[] args)
{
BaseDAL baseDAL = new BaseDAL();
{
List<User> users = baseDAL.FindAll<User>();
var b = baseDAL.Delete<User>(new User() {
Id = "de8be521-f1ec-4483-b124-0be342890507"
});
}
{
var b = baseDAL.Add<User>(new User
{
Id = Guid.NewGuid().ToString() ,
Name = "zs",
Sex = ,
Status = ,
BizCode = "",
CrateId = "",
TypeId = "",
TypeName = "admin",
CreateTime = DateTime.Now,
Account = "wjl",
Password = ""
});
var s = baseDAL.Update<User>(new User
{
Id = "4955d7e0-808f-4d50-af66-285e2a18966e",
Name = "zs",
Sex = ,
Status = ,
BizCode = "test value",
CrateId = "test value",
TypeId = "test value",
TypeName = "test value",
CreateTime = DateTime.Now,
Account = "test value",
Password = "test value"
});
}
Console.ReadLine();
}
至此,常规的CRUD已基本完成,我们不用再去关注复杂的sql,只需要操作实体类即可。
手写ORM入门篇(一)的更多相关文章
- 重学 Java 设计模式:实战中介者模式「按照Mybaits原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...
- 手写ORM
利用ORM把mysql中的数据封装成对象,通过对象点语法来获取mysql中的数据,所以自己手写一个ORM,方便我们操作数据 一.ORM:对象关系映射 类 >>> 数据库的一张表 对象 ...
- SqlSugar ORM 入门篇2 【查询】 让我们实现零SQL
SqlSugar在查询的功能是非常强大的,多表查询.分页查询 . 一对一查询.二级缓存.一对多查.WhenCase等复杂函数.Mapper功能.和拉姆达自定义扩展等,用好了是可以做到真正零SQL的一款 ...
- LambdaToSql(轻量级ORM) 入门篇 开源项目
为什么开发(背景) 最开始使用的是 sqlDbHelper,有微软的,有自己写的. 后来开始使用比较成熟的框架开发,使用过一段时间的Hibernate,后期主要使用 Entity FrameWork. ...
- 手写ORM第一版
ORM第一版: #Author = __rianley cheng__ #ORM 简易版 from mysql_ import Mysql class Fileld: def __init__(sel ...
- 基于springJDBC手写ORM框架
一.添加MySQLjar包依赖 二.结构 三.文件内容 (一).bean包 1.ColumnInfo.java 2.javaFiledInfo.java 3.TableInfo.java 4.Conf ...
- 手写ORM持久层框架(转)
工程结构: 本文测试的数据库为: 其中student的表结构为: 表数据: 配置文件 DB2.properties driver=com.mysql.jdbc.Driver url=jdbc\:mys ...
- 深入理解Mybatis(第一讲)——手写ORM框架(简易版Mybatis)
我们来自定义一个持久层框架,也就是Mybatis的简易版. 使用端的搭建 idea中新建maven工程IPersistence_test: 在resources目录下新建sqlMapConfig.xm ...
- 30个类手写Spring核心原理之自定义ORM(上)(6)
本文节选自<Spring 5核心原理> 1 实现思路概述 1.1 从ResultSet说起 说到ResultSet,有Java开发经验的"小伙伴"自然最熟悉不过了,不过 ...
随机推荐
- hotspot的安全区(saferegion)和安全点(safepoint)
1.通过OopMap完成根节点枚举 HotSpot虚拟机使用可达性分析算法确定对象是否可以被GC. 可达性分析算法从一系列GCRoot对象开始,向下搜索引用链,如果一个对象没有与任何GCRoot对象关 ...
- jquery实现select数据回显
[html] view plain copy <select class="div_select_re" id="edit_technicalGrade&q ...
- [Web] HTML5新特性history pushState/replaceState解决浏览器刷新缓存
转载: https://www.jianshu.com/p/cf63a1fabc86 现实开发中,例如‘商品列表页’跳转‘商品详情页’,返回时,不重新加载刷新页面,并且滚动到原来的位置. 1.首先,先 ...
- 引用fastclick.js或使用触屏监听 滑动屏幕报错:解决[Intervention] Unable to preventDefault inside passive event listener
使用fastClick.js所产生的一些问题 开发h5活动页时想到移动端会有300ms的延迟,于是便打算用fastClick.js解决. 页面引入fastClick.js后,滑动H5页面的时候发现谷歌 ...
- Netty - PooledByteBufAllocator
堆外内存, 就是非JVM管理的,由os管理的内存,等同于c语言里面的mallco分配的内存 故堆外内存的好处, 1. 不会有GC回收,缓解gc压力 2. 避免一次copy,发生到socket buff ...
- APISIX系列 | 使用 docker-apisix 安装APISIX服务
官方仓库:https://github.com/iresty/docker-apisix 官方仓库 拉取 git clone git@github.com:iresty/docker-apisix.g ...
- [转]iview render函数常用总结(vue render函数)
原文地址:https://blog.csdn.net/weixin_43206949/article/details/89385550 iview 的render函数就是vue的render函数ivi ...
- jetty demo实例启动
Jetty是一个提供HHTP服务器.HTTP客户端和javax.servlet容器的开源项目.Jetty和tomcat相比,是轻量级服务器,支持热拔插,可扩展性大tomcat集成了很多功能,个性化瘦身 ...
- 005_Philippines之行准备
一.去前必备的手续 (1)SSP SSP(Special Study Permit),又叫特殊学生许可,是由菲律宾移民局要求的,每一位前往菲律宾进行游学的学生都要办理的一种特殊许可,学校会统一进行办理 ...
- 统计git提交代码量
# a新增行数,d删除行数 git log --author="`git config --get user.name`" --pretty="%H" --a ...