手写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开发经验的"小伙伴"自然最熟悉不过了,不过 ...
随机推荐
- 【XR-4】题
题面 题解 由题,所求为方程\(y^2 = x^2 + ax + b\)的整数解数量. 两边同乘\(4\),可得\((2y)^2 = 4x^2 + 4ax + 4b\). 配方后得\((2y)^2 = ...
- Android Studio 之 Activity 的生命周期
翻转屏幕,会重新加载Activity package com.example.activitylivecycle; import android.os.Bundle; import android.u ...
- JDBC Api详解
一.什么是JDBC JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Jav ...
- CT窗宽位宽
先说一下CT值是什么 CT图像反映的是人体对X射线吸收的系数,但我们关心的是各组织结构的密度差异,即相对密度,如果某组织发生病变,其密度就会发生变化,但由于比较吸收系数非常繁琐,于是亨氏把组织器官对X ...
- Java编程思想之二 一切都是对象
2.1 用引用操作对象 每种编程语言都有自己的操作内存中元素的方式. 在Java中,一切都可以视为对象,因此可以采用单一的固定语法. 2.2 必须由你创建所有对象 一旦创建一个引用,就希望它能与一个新 ...
- hbuilderx - 常用快捷键操作
常用的操作有(缺少一个快捷键,就是选中行) 1. ctrl+/ 注释代码 2. ctrl+y 恢复撤销 3. ctrl+x 剪切 4. ctrl+z 撤销 5. ctrl+c 复制 6. ctrl+p ...
- [Web 测试] Jest单元测试的几个指标
三个参数代表什么? %stmts是语句覆盖率(statement coverage):是不是每个语句都执行了? %Branch分支覆盖率(branch coverage):是不是每个if代码块都执行了 ...
- exception: TypeError: Cannot read property '_modulesNamespaceMap' of undefined at getModuleByNamespac
用 Vue.extend 创造的组件构造器和组件,默认是不集成 store 和 router 的. 比如 main.js 中的这个,其实是挂载在根组件 vm 中.并不是注入到全局 Vue 中.所以你用 ...
- tp的增删改查的结果判断?
参考: https://blog.csdn.net/qq_27930635/article/details/78853908 总之, 要用 全等 来判断, = = = 注意, 不要再用 mysql_a ...
- org.springframework.web.method.ControllerAdviceBean#isApplicableToBeanType 作用
org.springframework.web.method.ControllerAdviceBean#isApplicableToBeanType(@Nullable Class<?> ...