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

近几年在项目中一直使用Dapper操作数据库,感觉其实现的DynamicParameters特别炫,所以尝试封装了一个类似的方法  [MyDbParameters],功能比较简单,仅覆盖了工作中用到的一部分功能,算是个简陋版吧。

一、SQL语句构造器,用于生成参数化查询、更新、插入的SQL语句

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyOrm.Commons;
using MyOrm.Reflections; namespace MyOrm.SqlBuilder
{
public class SqlServerBuilder
{
protected readonly string Prefix = "@"; #region 查询
public string Select(string table, string columns, string where, string sort, int top = )
{
if (table == null) throw new ArgumentNullException(nameof(table)); var sb = new StringBuilder("SELECT ");
if (top > )
{
sb.Append("TOP ").Append(top.ToString()).Append(" ");
} sb.Append(string.IsNullOrWhiteSpace(columns) ? "*" : columns); sb.Append(" FROM ").Append(table); if (!string.IsNullOrWhiteSpace(where))
{
sb.Append(" WHERE ").Append(where);
} if (!string.IsNullOrWhiteSpace(sort))
{
sb.Append(" ORDER BY ").Append(sort);
} return sb.ToString();
} public string PagingSelect(string table, string columns, string where, string sort, int pageIndex, int pageSize)
{
pageIndex = pageIndex <= ? : pageIndex;
pageSize = pageSize <= ? : pageSize;
where = string.IsNullOrWhiteSpace(where) ? "1=1" : where; if (pageIndex == )
{
var sql = Select(table, columns, where, sort, pageSize);
sql += $";SELECT @RecordCount=COUNT(0) FROM {table} WHERE {where}";
return sql;
} columns = string.IsNullOrWhiteSpace(columns) ? "*" : columns;
sort = string.IsNullOrWhiteSpace(sort) ? "(SELECT 1)" : sort; var sb = new StringBuilder();
sb.Append("SELECT ")
.Append(columns)
.Append(" FROM ")
.Append(table)
.Append(" WHERE ")
.Append(where)
.Append(" ORDER BY ")
.Append(sort)
.Append(" OFFSET ")
.Append((pageIndex - ) * pageSize)
.Append(" ROWS FETCH NEXT ")
.Append(pageSize)
.Append(" ROWS ONLY;");
sb.Append("SELECT @RecordCount=COUNT(0) FROM ")
.Append(table)
.Append(string.IsNullOrWhiteSpace(where) ? "" : " WHERE " + where); return sb.ToString();
} public string PagingSelect2008(string tables, string cols, string condition, string orderBy, int index, int size)
{
if (string.IsNullOrWhiteSpace(orderBy))
{
orderBy = "(select 1)";
} if (string.IsNullOrWhiteSpace(condition))
{
condition = "1=1";
} if (index == )
{
var sql =
$"SELECT TOP {size} {cols} FROM {tables} WHERE {condition} ORDER BY {orderBy};SELECT {Prefix}RecordCount=COUNT(0) FROM {tables} WHERE {condition}"; return sql;
}
else
{
var sb = new StringBuilder();
sb.Append("FROM ").Append(tables);
sb.Append(" WHERE ").Append(condition);
var sql = $@" WITH PAGEDDATA AS
(
SELECT TOP 100 PERCENT {cols}, ROW_NUMBER() OVER (ORDER BY {@orderBy}) AS FLUENTDATA_ROWNUMBER
{sb}
)
SELECT *
FROM PAGEDDATA
WHERE FLUENTDATA_ROWNUMBER BETWEEN {(index - 1) * size + 1} AND {index * size};
SELECT {Prefix}RecordCount=COUNT(0) FROM {tables} WHERE {condition}";
return sql;
}
}
#endregion #region 插入
public string InsertIfNotExists(MyEntity entityInfo, string where)
{
var sb = new StringBuilder();
sb.Append("IF NOT EXISTS (SELECT 1 FROM [")
.Append(entityInfo.TableName)
.Append("] WHERE ")
.Append(where)
.Append(")");
sb.Append(Insert(entityInfo));
return sb.ToString();
} public string Insert(MyEntity entityInfo)
{
if (entityInfo == null) throw new ArgumentNullException(nameof(entityInfo)); var sb = new StringBuilder();
var columns = new List<string>();
var parameters = new List<string>(); foreach (var prop in entityInfo.Properties.Where(p => !p.InsertIgnore))
{
columns.Add("[" + prop.FieldName + "]");
parameters.Add(Prefix + prop.Name);
} sb.Append("INSERT INTO [")
.Append(entityInfo.TableName)
.Append("] (")
.Append(string.Join(",", columns))
.Append(") VALUES (")
.Append(string.Join(",", parameters))
.Append(");SELECT SCOPE_IDENTITY();");
return sb.ToString();
}
#endregion #region 更新
public string Update(MyEntity entityInfo, string where)
{
if (entityInfo == null) throw new ArgumentNullException(nameof(entityInfo)); var sb = new StringBuilder();
sb.Append("UPDATE [")
.Append(entityInfo.TableName)
.Append("] SET "); var clauses = entityInfo.Properties.Where(p => !p.UpdateIgnore)
.Select(p => $"{p.FieldName}={Prefix}{p.Name}");
sb.Append(string.Join(",", clauses)); sb.Append(string.IsNullOrWhiteSpace(where) ? $" WHERE [{entityInfo.KeyColumn}]={Prefix}Id" : where); return sb.ToString();
} public string UpdateIgnore(MyEntity entityInfo, string[] propertyList, bool ignoreAttribute, string where)
{
if (entityInfo == null) throw new ArgumentNullException(nameof(entityInfo)); var properties = entityInfo.Properties; var updateProperties = ignoreAttribute
? properties.Where(p => !propertyList.Contains(p.Name)).ToList()
: properties.Where(p => !p.UpdateIgnore && !propertyList.Contains(p.Name)).ToList(); if (properties.Count == )
{
throw new ArgumentNullException(nameof(properties), "要更新的列为空");
} var sb = new StringBuilder();
sb.Append("UPDATE [")
.Append(entityInfo.TableName)
.Append("] SET "); var clauses = updateProperties.Select(p => $"{p.FieldName}={Prefix}{p.Name}");
sb.Append(string.Join(",", clauses));
sb.Append(string.IsNullOrWhiteSpace(where) ? $" WHERE [{entityInfo.KeyColumn}]={Prefix}Id" : where);
return sb.ToString();
} public string Update(string table, DbKvs kvs, string where)
{
if (kvs == null || kvs.Count == ) throw new ArgumentNullException(nameof(kvs));
if (string.IsNullOrWhiteSpace(table)) throw new ArgumentNullException(nameof(table)); var sb = new StringBuilder();
sb.Append("UPDATE [")
.Append(table)
.Append("] SET ");
var clauses = kvs.Select(kv => $"[{kv.Key}]={Prefix}{kv.Key}");
sb.Append(string.Join(",", clauses));
if (!string.IsNullOrWhiteSpace(where))
{
sb.Append(" WHERE ").Append(where);
} return sb.ToString();
}
#endregion
}
}

二、MyDbParameters,在Add(object obj)方法中还是用到了反射,没想好怎么优化这部分内容,先留个坑

注意:若添加了同名参数,后面的会覆盖前面的。

using System.Data;

namespace MyOrm.DbParameters
{
public class MyDbParameter
{
public string Name { get; set; } public object Value { get; set; } public ParameterDirection? Direction { get; set; }
} public class MyDbParameters
{
private readonly List<MyDbParameter> _dict = new List<MyDbParameter>(); private readonly string _prefix = "@"; public MyDbParameters()
{ } public MyDbParameters(string prefix)
{
_prefix = prefix;
} public SqlParameter[] Parameters
{
get
{
if (_dict.Count == )
{
return new SqlParameter[]{};
} var list = new List<SqlParameter>();
foreach (var item in _dict)
{
var param = new SqlParameter($@"{item.Name}", item.Value);
if (item.Direction != null)
{
param.Direction = item.Direction.Value;
}
list.Add(param);
} return list.ToArray();
}
} public void Add(string parameterName, object value)
{
var item = _dict.FirstOrDefault(d => d.Name == parameterName);
var newItem = new MyDbParameter {Name = parameterName, Value = value}; if (item == null)
{
_dict.Add(newItem);
}
else
{
item = newItem;
}
} public void Add(string parameterName, object value, ParameterDirection direction)
{
var item = _dict.FirstOrDefault(d => d.Name == parameterName);
var newItem = new MyDbParameter { Name = parameterName, Value = value, Direction = direction}; if (item == null)
{
_dict.Add(newItem);
}
else
{
item = newItem;
}
} public void Add(object obj)
{
if (obj is MyDbParameter parameter)
{
_dict.Add(parameter);
}
else if(obj is IEntity)
{
var entityInfo = MyEntityContainer.Get(obj.GetType());
foreach(var property in entityInfo.Properties.Where(p => p.IsMap))
{
Add(property.Name, property.PropertyInfo.GetValue(obj));
}
}
else
{
var properties = obj.GetType().GetProperties();
foreach (var property in properties.Where(p => p.PropertyType.IsValueType ||
p.PropertyType == typeof(string)))
{
Add(property.Name, property.GetValue(obj));
}
}
} public void AddParameters(MyDbParameters parameters)
{
foreach (var item in parameters._dict)
{
Add(item);
}
} public void Add(SqlParameter parameter)
{
Add(parameter.ParameterName, parameter.Value);
} public void Add(SqlParameter[] parameters)
{
foreach(var item in parameters)
{
Add(item);
}
}
}
}

使用方法:

var student = new Student {
Id = ,
Name = "张三"
} var updateParameters = new MyDbParameters();
updateParameters.Add(student); var searchParameters = new MyDbParameters();
searchParameters.Add("Name", "张三");
searchParameters.Add("Id", ); updateParameters.Add(searchParameters); // 获取SqlParameter[]
var sqlParameters = updateParameters.Parameters;

【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装的更多相关文章

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

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

  2. 【手撸一个ORM】第九步、orm默认配置类 MyDbConfiguration,一次配置,简化实例化流程

    这个实现比较简单,事实上可配置的项目很多,如有需要,请读者自行扩展 using System; namespace MyOrm { public class MyDbConfiguration { p ...

  3. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. CI公用模型

    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * SEO管理系统 -- 公用模型 ...

  2. findbugs规则

    FindBugs是基于Bug Patterns概念,查找javabytecode(.class文件)中的潜在bug,主要检查bytecode中的bug patterns,如NullPoint空指针检查 ...

  3. Java集合的有序无序问题和线程安全与否问题

    首先,清楚有序和无序是什么意思: 集合的有序.无序是指插入元素时,保持插入的顺序性,也就是先插入的元素优先放入集合的前面部分. 而排序是指插入元素后,集合中的元素是否自动排序.(例如升序排序) 1.有 ...

  4. bzoj 3685

    线段树 方法一: 值域线段树,递归去写的,每次节点存出现次数. 对于几个操作, 1,2 直接加减就好 ; 3,4 操作贪心往某一个方向找 .7也很简单,主要说前驱后继怎么找.我是先找这个数第几小,根据 ...

  5. bzoj 3771: Triple 快速傅里叶变换 FFT

    题目大意: 给出\(n\)个互不相同的物品,每个物品有价值\(x_i(x_i \leq 40000)\)如果可以从中取一个或两个或三个物品.问能够组合出来的所有价值和对应的方案数,全部输出.取值时,\ ...

  6. 解析Monte-Carlo算法(基本原理,理论基础,应用实践)

    引言 最近在和同学讨论研究Six Sigma(六西格玛)软件开发方法及CMMI相关问题时,遇到了需要使用Monte-Carlo算法模拟分布未知的多元一次概率密度分布问题.于是花了几天时间,通过查询相关 ...

  7. AtCoder Grand Contest 010 C:Cleaning

    题目传送门:https://agc010.contest.atcoder.jp/tasks/agc010_c 题目翻译 给你一棵树,每个点有个权值,每次操作可以选择两个度数为\(1\)的结点,然后让这 ...

  8. Java远程调用

    一.  概念: RMI全称是Remote Method Invocation-远程方法调用,其威力就体现在它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一.它支持 ...

  9. vijos:P1155集合位置(次短路)

    描述 每次有大的活动,大家都要在一起“聚一聚”,不管是去好乐迪,还是避风塘,或者汤姆熊,大家都要玩的痛快.还记得心语和花儿在跳舞机上的激情与释放,还记得草草的投篮技艺是如此的高超,还记得狗狗的枪法永远 ...

  10. shuts down an ExecutorService

    shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and ...