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>();
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的使用说明的更多相关文章

  1. 【手撸一个ORM】第六步、对象表达式解析和Select表达式解析

    说明 一个Orm自然不仅仅包含条件表达式,还会有如下的场景: OrderBy(s => s.StudentName) Select<StudentDto>(s => new S ...

  2. 【手撸一个ORM】第七步、SqlDataReader转实体

    说明 使用Expression(表达式目录树)转Entity的文章在园子里有很多,思路也大致也一样,我在前面有篇文章对解决思路有些说明,有兴趣的小伙伴可以看下 (传送门),刚接触表达式目录树时写的,不 ...

  3. 【手撸一个ORM】第十步、数据操作工具类 MyDb

    说明 其实就是数据库操作的一些封装,很久不用SqlCommand操作数据库了,看了点园子里的文章就直接上手写了,功能上没问题,但写法上是否完美高效无法保证,建议有需要的朋友自己重写,当然如果能把最佳实 ...

  4. 【手撸一个ORM】第一步、实体约定和描述

    一.约定 数据实体必须实现 IEntity 接口,该接口定义了一个int类型的Id属性,既每个实体必须有一个名称为Id的自增主键. 若数据表的主键列名称不是Id,可以通过 [MyKey("主 ...

  5. 【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装

    既然是数据库工具,自然少不了增删改查的sql语句,在这里将这些常用SQL拼接操作集成到 [SqlServerBuilder.cs] 当中,方便后面调用. 近几年在项目中一直使用Dapper操作数据库, ...

  6. 【手撸一个ORM】第四步、Expression(表达式目录树)扩展

    到这里,Orm的基架已经搭起来了,接下来就是激动人心的部分,表达式目录树转Sql语句,SqlDataReader转数据实体等等,但是在这之前,我们需要扩展下表达式目录树的方法,以方便后面的相关操作. ...

  7. 【手撸一个ORM】第五步、Expression(表达式目录树)转换为Where子句

    说明 在SQL中,查询.修改比较常用到WHERE子句,在这里根据使用场景不同,定义了两个类,一个用于查询,一个用于修改(插入)操作.原因是: 查询操作支持一级导航属性查询,如student.Schoo ...

  8. 【手撸一个ORM】第八步、查询工具类

    一.实体查询 using MyOrm.Commons; using MyOrm.DbParameters; using MyOrm.Expressions; using MyOrm.Mappers; ...

  9. 【手撸一个ORM】第二步、封装实体描述和实体属性描述

    一.实体属性描述 [MyProperty.cs] Name,属性名称 PropertyInfo,反射获取的属性信息,后面很多地方需要通过该属性获取对应的实体类型,或调用SetValue进行赋值 Fie ...

随机推荐

  1. 通过Jquery异步获取股票实时数据

    最近朋友让我帮他做个异步获取数据的程序,暂时服务器什么都没有,所以我就想先拿股票数据打个框架,方便后续开发和移植等事情 代码如下: <!-- 说明:股票看盘 作者:黑桃A 时间:2014-04- ...

  2. Poj 1887 Testing the CATCHER(LIS)

    一.Description A military contractor for the Department of Defense has just completed a series of pre ...

  3. HDU1698(线段树入门题)

    Just a Hook Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Descrip ...

  4. svn、git等比较---总结

    免费的版本控制系统: CVS:集中式的版本控制系统,必须联网,速度慢,CVS作为最早的开源而且免费的集中式版本控制系统,直到现在还有不少人在用.由于CVS自身设计的问题,会造成提交文件不完整,版本库莫 ...

  5. 【opencv学习笔记八】创建TrackBar轨迹条

    createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便.首先大家要记住,它往往会和一个回调函数配合起来使用.先看下他的函数 ...

  6. 【java并发编程艺术学习】(三)第二章 java并发机制的底层实现原理 学习记录(一) volatile

    章节介绍 这一章节主要学习java并发机制的底层实现原理.主要学习volatile.synchronized和原子操作的实现原理.Java中的大部分容器和框架都依赖于此. Java代码 ==经过编译= ...

  7. 每天一道算法题(1) ——不用乘除法求和1+2+…+n

    题目:求1+2+-+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句(A?B:C). 方法1:使用函数指针. typedef int (*fu ...

  8. SharePoint 2013 搜索高级配置

    SharePoint2013里面的搜索配置. 1.首先,新建页面,用于搜索, 2.添加搜索框.搜索结果部件: 选择<搜索>类别,找到”搜索框”.”搜索结果”两个部件,添加到页面: 3.配置 ...

  9. python包管理

    如果是python 项目目录,例如pycharm里新建的python项目,则可以通过from,import导入目录下的文件夹. 如果是普通文件目录,则代码里不能相对方式导入该目录下的文件夹,需要加入要 ...

  10. Entity Framework Code-First(9.1):DataAnnotations - Key Attribute

    DataAnnotations - Key Attribute: Key attribute can be applied to properties of a class. Default Code ...