一个简易的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 ...
随机推荐
- 【预定义】C语言预定义代码(宏、条件编译等)内容介绍【最全的保姆级别教程】
浅谈C语言预定义中的预定义符号,#define,以及符号#,##的相关运用 求个赞求个赞求个赞求个赞 谢谢 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一 ...
- 8.类--《Python编程:从入门到实践》
8.1 创建类 根据约定,在Python中,首字母大写的名称指的是类. 这个类定义中的括号是空的,因为我们要从空白创建这个类.在Python 2.7中创建类时,需要做细微的修改--在括号内包含单词ob ...
- 覆盖第三方jar包中的某一个类。妙!!
在我们日常的开发中,经常需要使用第三方的jar包,但是很多时候总是会发现第三方的jar包中的某一个类,有问题,但是又无法继承,因为你继承后 变成了你自己的,jar包中 调用的 还是 他自己内部包含的, ...
- .NET 云原生架构师训练营(模块二 基础巩固 引入)--学习笔记
2.1 引入 http协议 web server && web application framework .net 与 .net core asp .net core web api ...
- [刺客伍六七&黑客] 魔刀千刃evilblade的使用手册与开源
0x00 前言 2023.8.15 夜里 非常欢迎使用我的魔刀千刃,并且欢迎各位师傅对我的开源代码进行指导! -–Offense without defense, unparalleled in th ...
- Power BI 12 DAY
电商平台流量分析 案例练习 参数建模 建模-->新建参数 新建度量值使用SWITCH函数将需要的指标数据化 15.关键指标 = switch([指标选择 值],1,[1.访客数合计],2,[2. ...
- NC16645 [NOIP2007]矩阵取数游戏
题目链接 题目 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵 ...
- 复习一下JVM内存结构
一.程序计数器 程序计数器内存很小,可以看作是当前线程所执行字节码的行号指示器. 有了它,程序就能被正确的执行. 因为有线程切换的存在,则每个线程必须有各自独立的程序计数器,即线程私有的内存. 这里再 ...
- 使用OpenWrt实现IPv6 DDNS
OpenWrt 增加 crontab 任务 在/root/crontab/ 目录下, 创建脚本 ddns.sh #!/bin/sh # 远程php脚本的URL地址 SERVICE_URL=http:/ ...
- 【Unity3D】UGUI之InputField
1 InputField 属性面板 在 Hierarchy 窗口右键,选择 UI 列表里的 InputField(输入框)控件,即可创建 InputField 控件,选中创建的 InputFiel ...