对象关系映射(英语:(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入门篇(一)的更多相关文章

  1. 重学 Java 设计模式:实战中介者模式「按照Mybaits原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...

  2. 手写ORM

    利用ORM把mysql中的数据封装成对象,通过对象点语法来获取mysql中的数据,所以自己手写一个ORM,方便我们操作数据 一.ORM:对象关系映射 类 >>> 数据库的一张表 对象 ...

  3. SqlSugar ORM 入门篇2 【查询】 让我们实现零SQL

    SqlSugar在查询的功能是非常强大的,多表查询.分页查询 . 一对一查询.二级缓存.一对多查.WhenCase等复杂函数.Mapper功能.和拉姆达自定义扩展等,用好了是可以做到真正零SQL的一款 ...

  4. LambdaToSql(轻量级ORM) 入门篇 开源项目

    为什么开发(背景) 最开始使用的是 sqlDbHelper,有微软的,有自己写的. 后来开始使用比较成熟的框架开发,使用过一段时间的Hibernate,后期主要使用 Entity FrameWork. ...

  5. 手写ORM第一版

    ORM第一版: #Author = __rianley cheng__ #ORM 简易版 from mysql_ import Mysql class Fileld: def __init__(sel ...

  6. 基于springJDBC手写ORM框架

    一.添加MySQLjar包依赖 二.结构 三.文件内容 (一).bean包 1.ColumnInfo.java 2.javaFiledInfo.java 3.TableInfo.java 4.Conf ...

  7. 手写ORM持久层框架(转)

    工程结构: 本文测试的数据库为: 其中student的表结构为: 表数据: 配置文件 DB2.properties driver=com.mysql.jdbc.Driver url=jdbc\:mys ...

  8. 深入理解Mybatis(第一讲)——手写ORM框架(简易版Mybatis)

    我们来自定义一个持久层框架,也就是Mybatis的简易版. 使用端的搭建 idea中新建maven工程IPersistence_test: 在resources目录下新建sqlMapConfig.xm ...

  9. 30个类手写Spring核心原理之自定义ORM(上)(6)

    本文节选自<Spring 5核心原理> 1 实现思路概述 1.1 从ResultSet说起 说到ResultSet,有Java开发经验的"小伙伴"自然最熟悉不过了,不过 ...

随机推荐

  1. lintcode- 22.平面表

    题目描述 22. 平面列表 给定一个列表,该列表中的每个要素要么是个列表,要么是整数.将其变成一个只包含整数的简单列表. 样例 给定 [1,2,[1,2]],返回 [1,2,1,2]. 给定 [4,[ ...

  2. Dice Similarity Coefficent vs. IoU Dice系数和IoU

    Dice Similarity Coefficent vs. IoU Several readers emailed regarding the segmentation performance of ...

  3. UIAutomatorViewer、Inspector获取元素信息

    一.UIautomatorViewer 它是Android SDK的一个工具,如果安装了 Android SDK,就可以在cmd窗口直接输入uiautomatorviewer打开. 点击左上角的第二个 ...

  4. filebeat kafka java日志收集

    filebeat.modules:- module: kafka log: enabled: truefilebeat.prospectors:- type: log enabled: true pa ...

  5. 段地址机制以及段地址转换触发segmentation falt

    推动存储管理方式从固定分区到动态分区分配,进而又发展到分页存储管理方式的主要动力是提高内存利用率.可以实现一个内存用于多个程序同时执行而不会发生地址冲突.引入分段存储管理方式的目的,则主要是为了满足用 ...

  6. 【C++】C++中重载运算符和类型转换

    输入输出运算符 输入输出运算符 输入输出运算符 算术和关系运算符 相等运算符 关系运算符 赋值运算符 复合赋值运算符 下标运算符 递增和递减运算符 成员访问运算符 函数调用运算符 lambda是函数对 ...

  7. Could not create connection to database server. Attempted reconnect 3 times. Giving up.

    报出这个错误,可能原因: 1.检查MySQL数据库服务是否正常(包含检查服务名和密码),如果不正常,修复至正常为止: 2.maven工程中导入的mysql的jar版本和你的MySQL版本不相符,必须相 ...

  8. advanceInstaller制作中文安装界面

    AdvanceInstaller15.7 ,上述画框选择.

  9. chrome 报错 ERR_CERT_AUTHORITY_INVALID

    场景: 本地调试https/wss程序,使用了openssl自签名的证书,解决方法:添加到信任证书 根据以下图片流程操作 然后 打开selfsigned.cer 清空该网站缓存 参考资料: https ...

  10. 如何优雅的使用telnet测试端口连通性

    telnet命令是TELNET协议的用户接口,它支持两种模式:命令模式和会话模式,虽然telnet支持许多命令,但大部分情况下,我们只是使用它查看目标主机是否打开了某端口(默认是23). 其执行结果有 ...