一个简易的ORM框架的实现(二)
框架目标
什么是框架,框架能做到什么?
把一个方向的技术研发做封装,具备通用性,让使用框架的开发者用起来很轻松。
属性:
- 通用性
- 健壮性
- 稳定性
- 扩展性
- 高性能
- 组件化
- 跨平台
从零开始-搭建框架
- 建立项目
- 主键查询功能开发
- 绑定实体
一步一步的给大家推导:
一边写一边测试
从零开始--搭建框架
1. 创建项目
首先,创建两个类库一个名为Models保存我们的模型,一个名为DbProxy的类库保存我们对数据库的核心操作。
先进行我们查询功能的编写,暂时不考虑通用性。
public class DbProxyCore
{
public Commodity GetCommodity(int id)
{
string connectionString = "Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=*******";
Commodity commodity = new Commodity();
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = @"SELECT [Id]
,[ProductId]
,[CategoryId]
,[Title]
,[Price]
,[Url]
,[ImageUrl]
FROM [dbo].[Commodity] where Id="+id;
SqlCommand sqlCommand= connection.CreateCommand();
sqlCommand.CommandText = sql;
SqlDataReader reader= sqlCommand.ExecuteReader();//数据集的读取器
if (reader.Read())
{
commodity.Id = Convert.ToInt32(reader["Id"]);
commodity.ProductId = Convert.ToInt64(reader["ProductId"]);
commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);
commodity.Title = reader["Title"].ToString();
commodity.Price = Convert.ToDecimal(reader["Price"]);
commodity.Url = reader["Url"].ToString();
commodity.ImageUrl = reader["ImageUrl"].ToString();
}
}
return commodity;
}
}
当我们又创建一个其他的model对象的时候,就遇到一个问题,难道我们需要每次都进行不同对象的独有的方法的创建吗?
并不是,这里就可以通过泛型来完成它们独有的方法
暂时的改造
public T Find<T>(int id) where T : new()
{
string connectionString = """
Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=*********;
""";
T obj = new T();
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = @"SELECT [Id]
,[ProductId]
,[CategoryId]
,[Title]
,[Price]
,[Url]
,[ImageUrl]
FROM [dbo].[Commodity] where Id=" + id;
SqlCommand sqlCommand = connection.CreateCommand();
sqlCommand.CommandText = sql;
SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器
if (reader.Read())
{
//commodity.Id = Convert.ToInt32(reader["Id"]);
//commodity.ProductId = Convert.ToInt64(reader["ProductId"]);
//commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);
//commodity.Title = reader["Title"].ToString();
//commodity.Price = Convert.ToDecimal(reader["Price"]);
//commodity.Url = reader["Url"].ToString();
//commodity.ImageUrl = reader["ImageUrl"].ToString();
}
}
return obj;
}
尝试运行,可以正确的运行,并不报错。
我们要给对象的属性赋值,不能通过new一个对象,直接调用对象的属性赋值;
这里就可以使用到我们的反射技术。
public T Find<T>(int id) where T : new()
{
string connectionString = """
Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=7ujm&UJM;
""";
//T obj = new T();
Type type = typeof(T);
object? oResult = Activator.CreateInstance(type);
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = @"SELECT [Id]
,[ProductId]
,[CategoryId]
,[Title]
,[Price]
,[Url]
,[ImageUrl]
FROM [dbo].[Commodity] where Id=" + id;
SqlCommand sqlCommand = connection.CreateCommand();
sqlCommand.CommandText = sql;
SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器
if (reader.Read())
{
//commodity.Id = Convert.ToInt32(reader["Id"]);
//commodity.ProductId = Convert.ToInt64(reader["ProductId"]);
//commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);
//commodity.Title = reader["Title"].ToString();
//commodity.Price = Convert.ToDecimal(reader["Price"]);
//commodity.Url = reader["Url"].ToString();
//commodity.ImageUrl = reader["ImageUrl"].ToString();
foreach (var prop in type.GetProperties())
{
prop.SetValue(oResult, reader[prop.Name]);
}
}
}
return (T)oResult;
}
还有就是sql语句的问题,如何通过T来生成不同的sql语句。
sql语句应该依赖于我们的泛型T,也通过T来动态生成不同的SQl的语句。
public T Find<T>(int id) where T : new()
{
string connectionString = """
Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=********;
""";
//T obj = new T();
Type type = typeof(T);
object? oResult = Activator.CreateInstance(type);
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
List<string> propNameList = type.GetProperties().Select(c => c.Name).ToList();
string strProps = string.Join(",", propNameList);
string sql = $"SELECT {strProps} FROM {type.Name} where Id=" + id;
//以逗号分割的数据库表的字段名称。
SqlCommand sqlCommand = connection.CreateCommand();
sqlCommand.CommandText = sql;
SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器
if (reader.Read())
{
foreach (var prop in type.GetProperties())
{
prop.SetValue(oResult, reader[prop.Name]);
}
}
}
return (T)oResult;
}
处理DBNULL的问题
prop.SetValue(oResult, reader[prop.Name] is DBNull ? null : reader[prop.Name]) ;
这里还需要考虑如何避免传入如何的实体,导致报错的问题。
使用基类约束就能避免这个问题了。
一个简易的ORM框架的实现(二)的更多相关文章
- JDBC 学习笔记(十)—— 使用 JDBC 搭建一个简易的 ORM 框架
1. 数据映射 当我们获取到 ResultSet 之后,显然这个不是我们想要的数据结构. 数据库中的每一个表,在 Java 代码中,一定会有一个类与之对应,例如: package com.gerrar ...
- Summer——从头开始写一个简易的Spring框架
Summer--从头开始写一个简易的Spring框架 参考Spring框架实现一个简易类似的Java框架.计划陆续实现IOC.AOP.以及数据访问模块和事务控制模块. ...
- 从零实现一个简易的jQuery框架之二—核心思路详解
如何读源码 jQuery整体框架甚是复杂,也不易读懂.但是若想要在前端的路上走得更远.更好,研究分析前端的框架无疑是进阶路上必经之路.但是庞大的源码往往让我们不知道从何处开始下手.在很长的时间里我也被 ...
- c# 轻量级ORM框架 之 WhereHelper (二)
上篇文章发布了一些设计orm框架基层的和实现,有朋友提出WhereHelper是亮点,能被认可我表示高兴. 我就把WhereHelper设计思想和代码公开下. WhereHelper 的概念就是再拼接 ...
- 自己写一个java的mvc框架吧(二)
自己写一个mvc框架吧(二) 自己写代码的习惯 写一个框架吧,如果这个框架会用到一些配置上的东西,我自己习惯是先不用考虑这个配置文件应该是怎样的,什么形式的,先用一个java对象(比如叫 Config ...
- “造轮运动”之 ORM框架系列(二)~ 说说我心目中的ORM框架
ORM概念解析 首先梳理一下ORM的概念,ORM的全拼是Object Relation Mapping (对象关系映射),其中Object就是面向对象语言中的对象,本文使用的是c#语言,所以就是.ne ...
- Angularjs,WebAPI 搭建一个简易权限管理系统 —— 基本功能演示(二)
目录 前言 Angularjs名词与概念 Angularjs 基本功能演示 系统业务与实现 WebAPI项目主体结构 Angularjs 前端主体结构 基本功能演示(二) 非常抱歉这个月实在太忙,一直 ...
- 用Metaclass实现一个精简的ORM框架
存档: # -*- coding: utf-8 -*- class Field(object): def __init__(self, name, column_type): self.name = ...
- 一个简易的服务框架lsf
项目地址:https://github.com/jianliu/lsf 主体思路是利用javaassist实现一个代理类,代理java的接口,实现每一个方法,实现的代码是对每个方法的名称.参数构建一个 ...
- 轻量级ORM框架Dapper应用二:使用Dapper实现CURD操作
在上一篇文章中,讲解了如何安装Dapper,这篇文章中将会讲解如何使用Dapper使用CURD操作. 例子中使用到的实体类定义如下: using System; using System.Collec ...
随机推荐
- Python中的UnboundLocalError是什么错误?如何解决?
在一个月黑风高的夜晚,我们满心欢喜地写出以下代码: money = 10000 # 当前的财产,单位为元 def add_money(value): money += value print('当 ...
- Cnpack ctrl+alt+v 来回切换 变量声明区,和代码写区,非常方便
Cnpack ctrl+alt+v 来回切换 变量声明区,和代码写区,非常方便 非常方便
- 如何基于 spdlog 在编译期提供类 logrus 的日志接口
如何基于 spdlog 在编译期提供类 logrus 的日志接口 实现见 Github,代码简单,只有一个头文件. 前提 几年前看到戈君在知乎上的一篇文章,关于打印日志的一些经验总结: 实践下来很受用 ...
- 探索C语言的内存魔法:动态内存管理解析
欢迎大家来到贝蒂大讲堂 养成好习惯,先赞后看哦~ 所属专栏:C语言学习 贝蒂的主页:Betty's blog 1. 静态开辟内存 通过前面的学习,我们已经掌握了两种开辟内存的方法,分别是: #incl ...
- [WPF] 使用Silk.NET绘制D3D9或OpenGL内容并完美解决空域问题。
可扩展渲染控件实现的基本思路(D3D.OpenGL绘制所使用的基类): 首先创建一个抽象类 FramebufferBase,该类主要记录当前控件宽高和图像资源. public abstract cla ...
- 基于keras的胶囊网络(CapsNet)
1 简介 胶囊网络(CapsNet)由 Hinton 于2017年10月在<Dynamic Routing Between Capsules>中提出,目的在于解决 CNN 只能提取特征,而 ...
- 【OpenGL ES】凸镜贴图
1 前言 正方形图片贴到圆形上 中将正方形图片上的纹理映射到圆形模型上,同理,也可以将圆形上的纹理映射到凸镜的球形曲面上.如下图,最左边的竖条是原图片的截面(纹理坐标),最右边的竖条是变换后的顶点 ...
- Oracle正则表达式实战
原文链接:http://oracle-base.com/articles/misc/regular-expressions-support-in-oracle.php Introduction Exa ...
- spring boot中使用定时任务
1.在主类上添加EnableScheduling注解 package com.laoxu.gamedog; import org.springframework.boot.SpringApplicat ...
- 本地配置静态ip和dns及虚拟机