手写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开发经验的"小伙伴"自然最熟悉不过了,不过 ...
随机推荐
- js字符串连接
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> ...
- LCA的几种做法
P3379 LCA $ 1:$蜗牛爬式 void dfs(int u,int fa) { f[u]=fa;//预处理father for(int i=head[u]; i; i=e[i].nxt) i ...
- MyBatis传入参数为list、数组、map写法
1.foreach简单介绍: foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有item,index,collection,open,sep ...
- 第08组 Alpha冲刺(4/4)
小李的博客 作业博客 作业链接 组员1李昕晖(组长) 过去两天完成了哪些任务 文字/口头描述 11月20日了解各个小组的进度与难以攻破的地方,晚上安排开会,安排新的冲刺任务. 实现地图功能 展示Git ...
- ThreadPoolExecutor的坑
ExecutorService executorService = new ThreadPoolExecutor(0, MAX_THREAD_NUM, 60, TimeUnit.SECONDS, ne ...
- count(*) count(1) count(字段) 区别
count(*) count(1) count(字段) 区别 count(*)和count(字段) count(*)和count(字段)使用的目的是不一样的,在必须要使用count(字段)的时候还是要 ...
- docker 镜像制作
# wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.1-Linux-x86_64.sh# bash A ...
- Dart入门
要学Flutter必先学Dart,Dart和Java的语法很像,学过Java的人很快就能入手 Dart下载地址https://dart.dev/get-dart VSCode下载地址https://c ...
- ubuntu 16 typora 安装 ,14系统的不管用。。
# sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE linuxidc@linuxidc:~ ...
- Caused by java.lang.Exception Failed to send data to Kafka Expiring
flink 写kafka,报错,作业挂掉 Caused by: java.lang.Exception: Failed to send data to Kafka: Expiring 89 recor ...