DNetORM 是一款基于.net的轻量级的、轻配置的ORM框架,核心代码只有100K大小,支持SQLSERVER、MYSQL、ORACLE、SQLite数据库,DNetORM的核心思想是,将最接近原生的C#代码映射出最符合场景的sql语句,从而最大程度提升开发效率。
DNetORM使用起来非常简单,无需依赖配置文件,DNetORM拒绝封装过多的方法,这会造成使用的难度,只是封装了增删改查基本常用的一些方法,所以使用起来会非常简单。
DNetORM对于多表的联查进行了常规的封装支持了LEFT JOIN, INNER JOIN ,GROUP BY , ORDER BY, WHERE,对于复杂的写法,建议使用DNetORM提供的SQL查询接口,我们在开发中使用orm是为了提升开发效率,节省开发时间,这是为什么使用orm的目的,orm不是为了避免使用sql,实际开发中有很多查询语句会很复杂,如果依赖orm,首先orm即使支持的话也会写的很复杂,并不直观,以往有开发的筒子们在用linq实现相同的复杂一点的sql的时候,写个sql也就是5分钟,但是为了实现linq的写法写了半小时,还写的不正确,所以这些都是违背开发精神的。所以ORM是一个开发工具,它的出现就是为了节省开发时间、提升开发效率,使用orm可以帮你解决增删改的繁杂琐事,在查询上,orm帮你处理了大部分的单表查询,在多表的查询上,orm帮你处理简单的多表查询,帮你最快的获取数据,至于复杂的sql查询,直接使用sql查询接口。也许这种做法更加合理。
使用介绍
1.配置文件配置好连接串
connectionName的值对应连接串的name
<appSettings> <add key="connectionName" value="DB"/> </appSettings> <connectionStrings> <!--<add name="DB" connectionString="Data Source=localhost/XE;User Id=hr;Password=hr;" providerName="Oracle.ManagedDataAccess" />--> <!--<add name="DB" connectionString="host=localhost;database=test;uid=root;pwd=sa123456;charset=utf8;" providerName="MySql.Data.MySqlClient" />--> <add name="DB" connectionString="Data Source=localhost;Initial Catalog=test;Persist Security Info=True;User ID=sa;Password=123456;" providerName="System.Data.SqlClient" /> </connectionStrings>
2.定义好实体
public class Book { [Key(IsAutoGenerated = true)] public int? BookID { get; set; } public string BookName { get; set; } public int? AuthorID { get; set; } [NotColumn] public string AuthorName { get; set; } public double? Price { get; set; } public DateTime? PublishDate { get; set; } }
增删改查 目前支持sqlserver、mysql、oracle、sqlite
Add
using (DNetContext db = new DNetContext()) { var authorid = db.Add(new Author { AuthorName = "张三", Age = 30, IsValid = true }); db.Add(new Book { BookName = "从入门到放弃", Price = 20.5, PublishDate = DateTime.Now, AuthorID = authorid }); }
Update
更新总共有三种方式
1.传入一个实体,实体中的非null属性都会被更新,这是 一次安全的更新,因为如果不做这个判断,那么使用者传入一个实体的时候很可能初衷是只更新所赋值的那几个字段,但是却把其余未赋值的字段全部NULL化了,这就是一次很危险的操作。但是这同时带来了一个问题,就是通过实体更新无法更新一个字段为null,这时候解决方式可以是采用下面介绍的另外两种方式进行更新,也可以使用
db.UpdateOnlyFields<Author>(new Author { AuthorName = "123", Age = 20, AuthorID = 1, IsValid = true }, m => m, m => m.AuthorID == 1);
来强制更新指定的字段,相反如果不想更新实体中的特殊字段可以使用
db.UpdateIgnoreFields<Author>(new Author { AuthorName = "123", Age = 20, AuthorID = 1, IsValid = true }, m => m.AuthorName, m => m.AuthorID == 1);
2.传入一个Action<T> 类型的参数,此类型参数用于直接赋予变量,使用起来会很方便,譬如db.Update<Author>(m => m.AuthorName = "jack", m => m.AuthorID == authorid);但是缺点是无法依赖列进行更新
3.传入Expression<Func<T, T>>类型的参数,这是一个构造实体类的操作,这种写法会稍微麻烦一点,但是功能却是最强大的,支持依赖列进行更新,同时所有赋予的字段都会被更新,譬如:db.Update<Author>(m => new Author { AuthorName = m.AuthorName + "123", IsValid = null }, m => m.AuthorID == 1);
所以使用者在实际情况中根据需求来使用,一般情况下第二种方式完全满足开发场景了,特殊的情况使用第三种方式
using (DNetContext db = new DNetContext()) {
int authorid = db.GetMax<Author>(m => (int)m.AuthorID); db.Update<Author>(m => m.AuthorName = "jack", m => m.AuthorID == authorid); }
Delete
using (DNetContext db = new DNetContext()) { var author = db.GetSingle<Author>(m => true, q => q.OrderBy(m => m.AuthorID)); var effect = db.Delete(author); int authorid = db.GetMax<Author>(m => (int)m.AuthorID); db.Delete<Author>(m => m.AuthorID == authorid); }
Query
单表查询
支持以下sql格式
like
Contains、StartsWith、EndsWith
db.GetList<Author>(m => m.AuthorName.StartsWith("张三") && m.IsValid == true);
in
Contains 集合类
upper lower
ToUpper、ToLower
sql字符大小比较
CompareTo、Equals
var authors= db.GetList<Author>(m => m.AuthorName.CompareTo("123")>0 && m.IsValid == true);
charindex instr
IndexOf
var authors= db.GetList<Author>(m => m.AuthorName.IndexOf("123")>=0 && m.IsValid == true);
is null or = ''
IsNullOrEmpty
var authors= db.GetList<Author>(m =>string.IsNullOrEmpty(m.AuthorName) && m.IsValid == true);
类型转化、时间格式化
ToString
var authors= db.GetList<Book>(m =>((DateTime)m.PublishDate).ToString("yyyy-MM-dd")=="2017-10-11");
字符转时间
ToDateTime
var authors= db.GetList<Book>(m =>Convert.ToDateTime(m.PublishDate)>DateTime.Now.AddDays(-10));
整型转化
ToInt32
trim
TrimStart、TrimEnd、Trim
using (DNetContext db = new DNetContext()) { var author = db.GetSingle<Author>(m => true, q => q.OrderBy(m => m.AuthorID)); author = db.GetSingle<Author>(m => m.AuthorName.Contains("李四") && m.IsValid == true); var authors= db.GetList<Author>(m => m.AuthorName.StartsWith("张三") && m.IsValid == true); //获取动态类型 List<dynamic> name = db.GetDistinctList<Author>(m => m.AuthorName.StartsWith("王五") && m.IsValid == true,m=>m.AuthorName); List<string> name1 = db.GetDistinctList<Author,string>(m => m.AuthorName.StartsWith("王五") && m.IsValid == true, m => m.AuthorName);
//子查询写法
var books = db.GetList<Book>(m => SubQuery.GetList<Author>(n => n.AuthorID > 10, n => n.AuthorID).Contains(m.AuthorID));
books = db.GetList<Book>(m => m.AuthorID >= SubQuery.GetSingle<Author>(n => n.AuthorID == 10, n => n.AuthorID));
//获取最大值 var authorid = db.GetMax<Author>(m => (int)m.AuthorID); //动态查询 WhereBuilder<Author> where = new WhereBuilder<Author>(); where.And(m=>m.AuthorName.Contains("张三")); where.And(m => m.AuthorID==3); where.Or(m=>m.IsValid==true); db.GetList<Author>(where.WhereExpression); //分页参数由前台传来 PageFilter<Author> page = new PageFilter<Author> { PageIndex = 1, PageSize = 10 };
page.And(m => "jim green".Contains(m.AuthorName));
page.OrderBy(q => q.OrderBy(m => m.AuthorName).OrderByDescending(m => m.AuthorID));
PageDataSource<Author> pageSource = db.GetPage<Author>(page); }
JOIN Query 仅用于演示
join query支持两种方式,不限制参数别名JoinQuery和限制参数别名 JoinQueryAlias,譬如查询a b c 三张不同的表可以不限制别名,如果查询a b a 存在相同的表的时候就必须限制参数别名
var join = db.JoinQueryAlias.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .InnerJoin<Book, Author>((m1, n) => m1.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book>(m1 => new Book { BookName=m1.BookName+"123" }) .OrderByAsc<Book>(m => m.BookName); PageFilter page = new PageFilter { PageIndex = 1, PageSize = 10 };//分页参数前台传来 join.GetPage<Book>(page);
using (DNetContext db = new DNetContext()) { var books = db.JoinQuery.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book, Author>((m, n) => new { m.BookName, AuthorName = SqlFunctions.Count(n.AuthorName) }) .OrderByAsc<Book>(m => m.BookName) .GroupBy<Book, Author>((m, n) => new { m.BookName, n.AuthorName }) .Where<Book, Author>((m, n) => m.Price > 10 && n.IsValid == true) .GetList<Book>(); var join = db.JoinQuery.LeftJoin<Book, Author>((m, n) => m.AuthorID == n.AuthorID && n.IsValid == true) .Fields<Book, Author>((m, n) => new { m, n.AuthorName }) .OrderByAsc<Book>(m => m.BookName); PageFilter page = new PageFilter { PageIndex = 1, PageSize = 10 };//分页参数前台传来 join.GetPage<Book>(page); }
采用这种链式的写法,更接近于写一条sql的思路和方式,没有语法包袱,使用者会很快上手,通过Fields方式指定查询字段更方便获取一整张表的字段
SQL Query
using (DNetContext db = new DNetContext()) { StringBuilder sql = new StringBuilder(); List<DbParameter> parameters = new List<DbParameter>(); sql.AppendFormat(@"SELECT {0},A.AuthorName FROM Book B LEFT JOIN Author A ON A.AuthorID=B.AuthorID WHERE", SqlBuilder.GetSelectAllFields<Book>("B")); sql.Append(" B.BookID>@BookID "); parameters.Add(db.GetDbParameter("BookID",1)); PageDataSource<Book> books = db.GetPage<Book>(sql.ToString(),new PageFilter { PageIndex=1, PageSize=5 }, parameters.ToArray()); List<Book> bks = db.GetList<Book>(sql.ToString(), parameters.ToArray()); }
DbTransaction
using (DNetContext db = new DNetContext()) { db.DataBase.BeginTransaction(); try { List<Author> authors = new List<Author>(); for (int i = 0; i <= 100; i++) { authors.Add(new Author { AuthorName = "测试" + i.ToString(), Age = 20, IsValid = true }); } db.Add(authors); db.DataBase.Commit(); } catch { db.DataBase.Rollback(); } }
Distributed Transaction
DNetTransaction transaction = new DNetTransaction(); transaction.BeginTransaction(); try { using (DNetContext db = new DNetContext()) { List<Author> authors = new List<Author>(); for (int i = 0; i <= 100; i++) { authors.Add(new Author { AuthorName = "测试" + i.ToString(), Age = 20, IsValid = true }); } db.Add(authors); transaction.Commit(); } } catch { transaction.Rollback(); }
欢迎技术讨论 如有疑问可以在评论区讨论
源码地址
https://github.com/DNetORM/DNetORM4.0