zoukankan      html  css  js  c++  java
  • 【手撸一个ORM】第三步、SQL语句构造器和SqlParameter封装

    既然是数据库工具,自然少不了增删改查的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 = 0)
            {
                if (table == null) throw new ArgumentNullException(nameof(table));
    
                var sb = new StringBuilder("SELECT ");
                if (top > 0)
                {
                    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 <= 0 ? 1 : pageIndex;
                pageSize = pageSize <= 0 ? 20 : pageSize;
                where = string.IsNullOrWhiteSpace(where) ? "1=1" : where;
    
                if (pageIndex == 1)
                {
                    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 - 1) * 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 == 1)
                {
                    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 == 0)
                {
                    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 == 0) 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 == 0)
                    {
                        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 = 3,
        Name = "张三"
    }
    
    var updateParameters = new MyDbParameters();
    updateParameters.Add(student);
    
    var searchParameters = new MyDbParameters();
    searchParameters.Add("Name", "张三");
    searchParameters.Add("Id", 3);
    
    updateParameters.Add(searchParameters);
    
    // 获取SqlParameter[]
    var sqlParameters = updateParameters.Parameters;
  • 相关阅读:
    数组元素的查找1
    排序——选择排序
    排序——冒泡排序
    内部类——匿名内部类
    跳一跳
    数组元素换位置游戏
    六 java和Tomcat
    九 Jenkins持续集成
    八 ip和子网详解
    七 Git版本控制
  • 原文地址:https://www.cnblogs.com/diwu0510/p/10663348.html
Copyright © 2011-2022 走看看