【手撸一个ORM】使用说明

传送门

  1. 【手撸一个ORM】第一步、约定和实体描述
  2. 【手撸一个ORM】第二步、封装实体描述和实体属性描述
  3. 【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装
  4. 【手撸一个ORM】第四步、Expression(表达式目录树)扩展
  5. 【手撸一个ORM】第五步、查询条件表达式目录树解析和插入、更新查询目录树解析
  6. 【手撸一个ORM】第六步、对象表达式解析和Select表达式解析
  7. 【手撸一个ORM】第七步、SqlDataReader转实体
  8. 【手撸一个ORM】第八步、实体查询和按需查询
  9. 【手撸一个ORM】第九步、orm默认配置类
  10. 【手撸一个ORM】第十步、数据库查询工具类 MyDb

约定

数据实体对象继承自 IEntity 接口,该接口定义了一个 int 类型的Id属性。

public interface IEntity
{
    int Id { get; set; }
}

// 数据实体类
public class Student : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ClazzId { get; set; }
    public Clazz Clazz { get; set; }

    // 更新时忽略该属性
    [MyColumn(UpdateIgnore = true)]
    public DateTime CreateAt { get; set; }
}

public class Clazz : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

导航属性

如上面定义的Student类,导航属性Clazz默认外键为ClazzId,如需显式指定外键,可使用[MyForeignKey("FKClazzId")]修饰Clazz属性,这样查询时就可以通过Include(s => s.Clazz)查找到相关的Clazz信息,默认仅支持Left Join。

实体描述

MyTableAttribute(string tableName)

用于描述实体类,若实体名称与表名不同,需要使用此描述指定表名

MyKeyAttribute(string keyName)

用于描述实体的主键,若主键列不为Id,需使用词描述指定主键对应的列名

MyColumnAttribute(string ColumnName,bool Ignore,bool InsertIgnore, bool UpdateIgnore)

列描述,可指定对应的列名,Ignore=true 插入和修改时都忽略此字段,InsertIgnore=true 插入时忽略, UpdateIgnore=true 修改时忽略

MyForeignKeyAttribute(string ForeignKey, string MasterKey)

若外键名非 导航属性名+"Id",则需通过ForeignKey指定,MasterKey默认为Id,若不是通过Id进行关联或关联表的主键名不是Id,则需要通过此MasterKey指定

用法

实例化对象:

var db = new MyDb("DataSource=.;Database=Test;USER ID=sa;Password=1234");

// 或者在global中定义默认配置,使用时只要 var db = MyDb.New(); 即可。
// MyDb.New()等同于 new MyDb();
MyMiniOrmConfiguration.Init(ConfigurationManager.AppSettings["DefaultConnectionString"]);

查询单个实体:

var student = db.Load<Student>(1);

var student = db.Load<Student>(s => s.Name == "张三");

查询多个实体:

var student = db.Fetch<Student>();

var student = db.PageList<T>(2, 10, out var recordCount, s => s.Name.Contains("张三"), s=>s.Name);

Fluent 查询

var query = db.Query<Student>()
    .Include(s => s.Clazz)
    .Where(s => s.CreateAt > DateTime.Today.AddDays(-1))
    .OrderBy(s => s.Clazz.Id)
    .ThenOrderByDesc(s => s.Name);

var student = query.FirstOrDefault();
var students = query.ToList();
var students2 = query.ToPageList(2, 2, out var recordCount);

Select 查询

var query = db.Query<Student>()
    .Include(s => s.Clazz)
    .Where(s => s.CreateAt > DateTime.Today.AddDays(-1))
    .OrderBy(s => s.Clazz.Id)
    .ThenOrderByDesc(s => s.Name);

var student = query.Select<StudentDto>(s => new StudentDto { s.Id, s.StudentName, SchoolName = s.School.Name }).ToList();
var student = query.Select<StudentDto>(s => new StudentDto { s.Id, s.StudentName, SchoolName = s.School.Name }).ToPageList(2, 2, out var recordCount);

插入

var student = new Student
{
    Name = "张三",
    ClazzId = 1,
    CreateAt = DateTime.Now
};
db.Insert(student);    // 会将新产生的Id赋值到student.Id属性
Console.WriteLine($"{student.Id}");

// 批量插入

var students = new List<Student>
{
    new Student {Name = "张三", ClazzId = 1, CreateAt = DateTime.Now},
    new Student {Name = "李四", ClazzId = 1, CreateAt = DateTime.Now},
    new Student {Name = "王五", ClazzId = 1, CreateAt = DateTime.Now},
    new Student {Name = "赵六", ClazzId = 1, CreateAt = DateTime.Now}
};

db.Insert(students);

foreach (var stu in students)
{
    Console.WriteLine($"{stu.Id}-{stu.Name}");
}

// 如果不存在,则插入
// 如限制用户名不能重复 InsertIfNotExist(user, u => u.Name == user.Name)

int InsertIfNotExists<T>(T entity, Expression<Func<T, bool>> where) where T : class, IEntity, new()

更新

var student = db.Load<Student>(1);
student.Name = student.Name + "修改过";
var result = db.Update(student);

// 批量更新
var students = db.Fetch<Student>(s => s.Id > 1);
foreach (var student in students)
{
    student.Name += student.Name + "批量修改过";
}
var count = db.Update(students);
Console.WriteLine($"修改了 {count} 行");

// 如果不存在则更新
// UpdateIfNotExists(user, u=>u.Name == user.Name && u.Id != user.Id)

int UpdateIfNotExits<T>(T entity, Expression<Func<T, bool>> where)

更新-注意,以下内容未经过测试

// 通过Id修改指定列
db.Update<Student>(1, DbKvs.New().Add("Name", "张三"));

var student = db.Load<Student>(1);
student.Name = student.Name + "测试修改";
student.ClazzId = 2;

// 更新指定对象的指定属性(指定忽略属性)
// 注意,下面方法传入的是属性名而不是列名

var count = db.UpdateInclude<Student>(student, new[] {"Name", "ClazzId"});
var count2 = db.UpdateInclude<Student>(student, s => new { s.Name, s.ClazzId };
var count3 = db.UpdateIgnore<Student>(student, new[] {"CreateAt"});
var count4 = db.UpdateInclude<Student>(student, s => new { s.CreateAt, s.Creator, s.IsDel };

// 通过指定条件修改指定列,注意第一个参数传入的是属性名而不是列名

db.Update<Student>(DbKvs.New().Add("ClazzId", 2), s => s.ClazzId == 1);

删除

// 如果实体继承ISoftDelete,此方法将IsDel列赋值为0,可通过传入 isForce=true,强制delete

// int Delete<T>(int id, bool isForce = false) where T : class, IEntity, new()
db.Delete<Student>(1, true);

// int Delete<T>(IEnumerable<int> idList, bool isForce = false) where T : class, IEntity, new()
db.Delete<Student>(new[] {1,2,3}, true);

原文地址:https://www.cnblogs.com/diwu0510/p/10663755.html

时间: 2024-10-30 07:11:26

【手撸一个ORM】使用说明的相关文章

使用Java Socket手撸一个http服务器

原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomcat的底层是怎么支持http服务的呢?大名鼎鼎的Servlet又是什么东西呢,该怎么使用呢? 在初学java时,socket编程是逃不掉的一章:虽然在实际业务项目中,使用这个的可能性基本为0,本篇博文将主要介绍如何使用socket来实现一个简单的http服务器功能,提供常见的get/post请求支持

手撸一个SpringBoot的Starter,简单易上手

前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发SpringBoot项目变得简单.实际上Starter简单来说就是Spring+SpringMVC开发的.话不多说开始撸代码 1.创建项目 首先在idea中创建SpringBoot项目,并首先创建一个BeautyProperties类,代码代码如下: package com.mystarter; im

以鶸ice为例,手撸一个解释器(一)明确目标

代码地址 # HelloWorld.ice print("hello, world") 前言(废话) 其实从开始学习编译原理到现在已经有快半年的时间了,但是其间常常不能坚持看下去龙书(经常三天打鱼两天晒网,更何况每次打鱼不到半小时就累得不行又会放下书(笑)),截至到现在只勉强看完了前六章的部分,半年间其它事也没有做,其实想想上大学已经快两年了还是一事无成,知识也没有学到,不免觉得很羞愧. 暑假也要到了,这个学期马上也要结束了,临近大二结束之际,还是尝试着写一下以前想写的玩具吧,而本系列

来手撸一个小小小小小&quot;3D引擎&quot;

开始的唠叨 说是3D引擎确实有点过于博眼球了,其实就是实现了一个透视投影,当然也不是那么简单的. 此篇文章是纯粹给小白看的 高手请勿喷 .也称之为小向带你图形学入门基础 . 哇哈哈哈哈 一说到做一个3D画面的东东 一说总是到DirectX  OpenGL 这些玩意儿 我们这些菜鸟总是 想到哇擦擦 哇C++的   哇 计算机图形学好难.这玩意儿难度好大.其实就那么回事儿 ,DirectX OpenGL 只是工具 而已, 只要把原理搞懂了 你看我用low逼的GDI照样给你绘制一个3D物体 可以这样说

手撸一个Vue滚动加载自定义指令

用Vue在移动端做滚动加载,使用mint-ui框架, InfiniteScroll指令loadmore组件,在uc浏览器和qq浏览器都无法触发.无奈我只能自己写了. 决定用vue 的自定义指令 写滚动加载. 核心的api document.body.scrollTop 滚动条滚动的距离 (这个有兼容性问题,兼容性写法) let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body

99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!

罗曼罗兰说过:世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 Lombok,让你理解这个热门技术背后的执行原理,以及它的优缺点分析. 简介 在讲原理之前,我们先来复习一下 Lombok (老司机可以直接跳过本段看原理部分的内容). Lombok 是一个非常热门的开源项目 (https://github.com/rzwitserloot/lomb

.NET手撸2048小游戏

.NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEngine,从空白窗口开始,演示如何"手撸"2048小游戏,并在编码过程中感受C#的魅力和.NET编程的快乐. 说明:FlysEngine是封装于Direct2D,重复本文示例,只需在.NET Core 3.0下安装NuGet包FlysEngine.Desktop即可. 并不一定非要做一层封装

编译原理 - 1 手撸状态机词法分析器

感谢vczh轮子叔的坑了的教程,我的编译原理第一次入了个门,词法分析写完了,今后可以看看书继续往下学了. http://www.cppblog.com/vczh/archive/2014/03/02/206014.html 词法分析,就是对于一段代码,把他们分割成一个个的token,同时记录他们的行列号,丢掉不必要的信息,这个词法分析器很简单,简单的状态机就能胜任,用正则就没有自己造轮子的快感了,所以要自己手撸状态机拆token出来. 模仿vczh的语言,我的语言包括了以下要素 标识符:大小写字

Haskell手撸Softmax回归实现MNIST手写识别

Haskell手撸Softmax回归实现MNIST手写识别 前言 初学Haskell,看的书是Learn You a Haskell for Great Good, 才刚看到Making Our Own Types and Typeclasses这一章. 为了加深对Haskell的理解,便动手写了个Softmax回归.纯粹造轮子,只用了base. 显示图片虽然用了OpenGL,但是本文不会提到关于OpenGL的内容.虽说是造轮子, 但是这轮子造得还是使我受益匪浅.Softmax回归方面的内容参考