手写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开发经验的"小伙伴"自然最熟悉不过了,不过 ...
随机推荐
- python 操作es
Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上. Lucene 可能是目前存在的,不论开源还是私有的,拥有最先进,高性能和全功能搜索 ...
- mybatis ResultHandler vs ResultSetHandler及自定义扩展
ResultSetHandler是mybatis的关键类之一,用于对jdbc返回的ResultSet进行映射处理,其中包括列前缀处理,逻辑分页,鉴别器(Discriminator,基于值实现动态映射列 ...
- -[UITableView copyWithZone:]: unrecognized selector sent to instance 0x7XXXXXX00
-[UITableView copyWithZone:]: unrecognized selector sent to instance 0x7XXXXXX00 -[Class copyWithZon ...
- PHPUnit 单元测试教程
一.官网下载对应 PHP 版本的代码库 https://phpunit.de/getting-started-with-phpunit.html 二.安装 PHPUnit 官网提供了两种方法安装 1. ...
- FineReport简单上手
一.简介 FineReport是一个企业级报表制作.分析和展示工具 官网可以下载个人版进行体验学习:(windows版本设计器) https://www.finereport.com/product/ ...
- python获取文件路径
摘自:https://blog.csdn.net/Poo_Chai/article/details/89764001 import os root_path = os.path.abspath(os. ...
- spark org.apache.spark.ml.linalg.DenseVector cannot be cast to org.apache.spark.ml.linalg.SparseVector
在使用 import org.apache.spark.ml.feature.VectorAssembler 转换特征后,想要放入 import org.apache.spark.mllib.clas ...
- Spring Boot JDBC:加载DataSource过程的源码分析及yml中DataSource的配置
装载至:https://www.cnblogs.com/storml/p/8611388.html Spring Boot实现了自动加载DataSource及相关配置.当然,使用时加上@EnableA ...
- 关于Oracle报 ORA-00600: 内部错误代码, 参数: [kkqcscpopn_Int: 0], [], [], [], [], [], [], [], [], [], [], []解决
服务器上有的Oracle版本是11.2.0.1.0,但是用到了mybatis-PageHelper分页插件会报这个错误. 下面说说我是怎么遇到这个错误的:同事写的这个功能点是用到了前台分页,是正常的没 ...
- 【更新】Java发送邮件:个人邮箱(QQ & 网易163)+企业邮箱+Android
这次把两种情况仔细说一下,因为好多人问啦. 第一种:企业邮箱 这里在这一篇已经说的很清楚了,这次不过是建立个maven工程,引入了最新的javamail依赖,代码优化了一下.直接上代码 pom < ...