一个简易的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#写了一个小工具,主要功能是随机读取图片并合成一张长图.最近在使用的时候发现个问题,原图片宽度是1080,合成后的图片宽度也是1080,但是合成后的图片没有显示全,就像下面这样 原图 ...
- 内存池是什么原理?|内存池简易模拟实现|为学习高并发内存池tcmalloc做准备
前言 那么这里博主先安利一些干货满满的专栏了! 这两个都是博主在学习Linux操作系统过程中的记录,希望对大家的学习有帮助! 操作系统Operating Syshttps://blog.csdn.ne ...
- springboot log 没落盘
在配置文件中增加了下面的配置并不起作用. logging.file=/xx/xx.log 是因为在 springboot 2.2 版本之后上面的采纳数已经被废弃,需要用下面新的参数: logging. ...
- 《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(中)
第 5 章 使用 Entity Framework Core 5.3 重构仓储类 创建一个通用仓储接口 namespace Library.API.Services { public interfac ...
- Linux-find命令报错: missing argument to `-exec'
报错提示:find: missing argument to `-exec' 今天写一个清理脚本,用到了find命令.本来是这么写的: find . -type f -mtime +7 -name & ...
- 初步体验通过 Semantic Kernel 与自己部署的通义千问开源大模型进行对话
春节之前被 Semantic Kernel 所吸引,开始了解它,学习它. 在写这篇博文之前读了一些英文博文,顺便在这里分享一下: Intro to Semantic Kernel – Part One ...
- JS Leetcode 451. 根据字符出现频率排序题解分析
壹 ❀ 引 大前天做的一道题,昨天发版到11点,前天聚餐,一直没时间整理,今天下班闲来无事,还是做个简单思路整理.本题来自LeetCode 451. 根据字符出现频率排序,难度中等,其实整理下思路,其 ...
- JS Leetcode 1370. 上升下降字符串 题解分析,桶排序与charCodeAt fromCharCode妙用
壹 ❀ 引 本题来自LeetCode1370. 上升下降字符串,难度简单,是一道考察对于字符串遍历熟练度的题目,题目描述如下: 给你一个字符串 s ,请你根据下面的算法重新构造字符串: 从 s 中选出 ...
- mysql插入表中的中文字符显示为乱码或问号的解决方法
mysql中文显示乱码或者问号是因为选用的编码不对或者编码不一致造成的,最简单的方法就是修改mysql的配置文件my.cnf.在[mydqld]和[client]段加入 default-charact ...
- Oracle 表压缩(Table Compression)技术介绍
Oracle 表压缩(Table Compression)介绍 1.官方文档说法: As your database grows in size, consider using table compr ...