1. 程式人生 > >【手擼一個ORM】使用說明

【手擼一個ORM】使用說明

ttr 內容 reat lse 列名 def each test eat

傳送門

  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);

【手擼一個ORM】使用說明