【手撸一个ORM】MyOrm的使用说明
- 【手撸一个ORM】第一步、约定和实体描述
- 【手撸一个ORM】第二步、封装实体描述和实体属性描述
- 【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装
- 【手撸一个ORM】第四步、Expression(表达式目录树)扩展
- 【手撸一个ORM】第五步、查询条件表达式目录树解析和插入、更新查询目录树解析
- 【手撸一个ORM】第六步、对象表达式解析和Select表达式解析
- 【手撸一个ORM】第七步、SqlDataReader转实体
- 【手撸一个ORM】第八步、实体查询和按需查询
- 【手撸一个ORM】第九步、orm默认配置类
- 【手撸一个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>();
- var student = db.Load<Student>(s => s.Name == "张三");
查询多个实体:
- var student = db.Fetch<Student>();
- var student = db.PageList<T>(, , 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(-))
- .OrderBy(s => s.Clazz.Id)
- .ThenOrderByDesc(s => s.Name);
- var student = query.FirstOrDefault();
- var students = query.ToList();
- var students2 = query.ToPageList(, , out var recordCount);
Select 查询
- var query = db.Query<Student>()
- .Include(s => s.Clazz)
- .Where(s => s.CreateAt > DateTime.Today.AddDays(-))
- .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(, , out var recordCount);
插入
- var student = new Student
- {
- Name = "张三",
- ClazzId = ,
- CreateAt = DateTime.Now
- };
- db.Insert(student); // 会将新产生的Id赋值到student.Id属性
- Console.WriteLine($"{student.Id}");
- // 批量插入
- var students = new List<Student>
- {
- new Student {Name = "张三", ClazzId = , CreateAt = DateTime.Now},
- new Student {Name = "李四", ClazzId = , CreateAt = DateTime.Now},
- new Student {Name = "王五", ClazzId = , CreateAt = DateTime.Now},
- new Student {Name = "赵六", ClazzId = , 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>();
- student.Name = student.Name + "修改过";
- var result = db.Update(student);
- // 批量更新
- var students = db.Fetch<Student>(s => s.Id > );
- 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>(, DbKvs.New().Add("Name", "张三"));
- var student = db.Load<Student>();
- student.Name = student.Name + "测试修改";
- student.ClazzId = ;
- // 更新指定对象的指定属性(指定忽略属性)
- // 注意,下面方法传入的是属性名而不是列名
- 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", ), s => s.ClazzId == );
删除
- // 如果实体继承ISoftDelete,此方法将IsDel列赋值为0,可通过传入 isForce=true,强制delete
- // int Delete<T>(int id, bool isForce = false) where T : class, IEntity, new()
- db.Delete<Student>(, true);
- // int Delete<T>(IEnumerable<int> idList, bool isForce = false) where T : class, IEntity, new()
- db.Delete<Student>(new[] {,,}, true);
【手撸一个ORM】MyOrm的使用说明的更多相关文章
- 【手撸一个ORM】第六步、对象表达式解析和Select表达式解析
说明 一个Orm自然不仅仅包含条件表达式,还会有如下的场景: OrderBy(s => s.StudentName) Select<StudentDto>(s => new S ...
- 【手撸一个ORM】第七步、SqlDataReader转实体
说明 使用Expression(表达式目录树)转Entity的文章在园子里有很多,思路也大致也一样,我在前面有篇文章对解决思路有些说明,有兴趣的小伙伴可以看下 (传送门),刚接触表达式目录树时写的,不 ...
- 【手撸一个ORM】第十步、数据操作工具类 MyDb
说明 其实就是数据库操作的一些封装,很久不用SqlCommand操作数据库了,看了点园子里的文章就直接上手写了,功能上没问题,但写法上是否完美高效无法保证,建议有需要的朋友自己重写,当然如果能把最佳实 ...
- 【手撸一个ORM】第一步、实体约定和描述
一.约定 数据实体必须实现 IEntity 接口,该接口定义了一个int类型的Id属性,既每个实体必须有一个名称为Id的自增主键. 若数据表的主键列名称不是Id,可以通过 [MyKey("主 ...
- 【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装
既然是数据库工具,自然少不了增删改查的sql语句,在这里将这些常用SQL拼接操作集成到 [SqlServerBuilder.cs] 当中,方便后面调用. 近几年在项目中一直使用Dapper操作数据库, ...
- 【手撸一个ORM】第四步、Expression(表达式目录树)扩展
到这里,Orm的基架已经搭起来了,接下来就是激动人心的部分,表达式目录树转Sql语句,SqlDataReader转数据实体等等,但是在这之前,我们需要扩展下表达式目录树的方法,以方便后面的相关操作. ...
- 【手撸一个ORM】第五步、Expression(表达式目录树)转换为Where子句
说明 在SQL中,查询.修改比较常用到WHERE子句,在这里根据使用场景不同,定义了两个类,一个用于查询,一个用于修改(插入)操作.原因是: 查询操作支持一级导航属性查询,如student.Schoo ...
- 【手撸一个ORM】第八步、查询工具类
一.实体查询 using MyOrm.Commons; using MyOrm.DbParameters; using MyOrm.Expressions; using MyOrm.Mappers; ...
- 【手撸一个ORM】第二步、封装实体描述和实体属性描述
一.实体属性描述 [MyProperty.cs] Name,属性名称 PropertyInfo,反射获取的属性信息,后面很多地方需要通过该属性获取对应的实体类型,或调用SetValue进行赋值 Fie ...
随机推荐
- NOIp2018集训test-10-16 (bike day2)
“毕姥爷:今天的题好简单啊,你们怎么考得这么烂啊,如果是noip你们就凉透了啊“ 今天的题难度应该是3.2.1递减的,但是我不知道哪根筋没搭对,平时我最多1h多就弃题了,今天硬生生写了2h20min的 ...
- Hibernate Validator--创建自己的约束规则
尽管Bean Validation API定义了一大堆标准的约束条件, 但是肯定还是有这些约束不能满足我们需求的时候, 在这种情况下, 你可以根据你的特定的校验需求来创建自己的约束条件. 3.1. 创 ...
- spring扩展点之四:Spring Aware容器感知技术,BeanNameAware和BeanFactoryAware接口,springboot中的EnvironmentAware
aware:英 [əˈweə(r)] 美 [əˈwer] adj.意识到的;知道的;觉察到的 XXXAware在spring里表示对XXX感知,实现XXXAware接口,并通过实现对应的set-XXX ...
- WPF实现右键菜单
ContextMenu类就是用来做右键菜单的对象,对于任何的控件都可以进行对ContextMenu属性的操作进行设置右键菜单的功能. 下面代码就是对一个按钮添加一个WPF右键菜单的功能: < B ...
- Asp.net 实现只能允许一个账号同时只能在一个地方登录
先上帮助类: /// <summary> /// 单点登录帮助类 /// </summary> public class SSOHelper { /// <summary ...
- Matlab数据类型的转换
Matlab中有15种基本数据类型,主要是整型.浮点.逻辑.字符.日期和时间.结构数组.单元格数组以及函数句柄等. 1.整型:(int8:uint8:int16:uint16:int32:uint32 ...
- Angular06 组件、模块、父子组件之间的数据传递
1 创建组件 进入到angular项目的根目录,执行如下命令 ng g component test-component 注意:执行完上述命令后在angular项目的src/app文件夹下就会多出一个 ...
- Mail.Ru Cup 2018 Round 2C(__gcd)
#include<bits/stdc++.h>using namespace std;long long mx(long long l1,long long r1,long long l2 ...
- java排序算法(持续更新)
package exception; import java.util.Arrays; public class Sort { public static void main(String[] arg ...
- uva 1153 顾客是上帝(贪心)
uva 1153 顾客是上帝(贪心) 有n个工作,已知每个工作需要的时间q[i]和截止时间d[i](必须在此前完成),最多能完成多少个工作?工作只能串行完成,第一项任务开始的时间不早于时刻0. 这道题 ...