文件源码https://files.cnblogs.com/files/pilgrim/StudentManage.rar

1、通过正常编写sql语句和顺序写代码

  正常编写sql语句是常用的方式,也是初学者最易掌握的(比如我)。直接使用sql进行拼装,但当设计多个实体对象时,就需要写多个对应的sql语句,需要使用代码码。这个方法里,我是用了反射和属性字段的方式,来获取和设置相关的对象值。

/// <summary>
/// 正常编写sql语句和顺序写代码
/// </summary>
public class SqlHelper //: IDBHelper
{
    /// <summary>
    /// Sql连接
    /// </summary>
    protected SqlConnection connection = new SqlConnection();

    public SqlHelper()
    {
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
        builder.DataSource = @"(LocalDB)\MSSQLLocalDB";
        builder.AttachDBFilename = @"C:\Users\Nigel\Desktop\StudentManage\StudentManage\Database1.mdf";
        builder.IntegratedSecurity = true;
        connection.ConnectionString = builder.ConnectionString;
    }

    /// <summary>
    /// 查询一个对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    public virtual T SelectOne<T>(int id) where T : class, IModel, new()
    {
        T t = new T();

        Type type = typeof(T);
        //没有应用特性的情况:此时,表名与类名相同、属性名和数据库字段名相同
        string sql = $"select * from [{type.Name}] where id = {id}";
        try
        {
            connection.Open();
            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            if (reader.Read())
            {
                PropertyInfo[] infos = type.GetProperties();
                foreach (var info in infos)
                {
                    if (info.CanWrite)
                    {
                        //设置对应的值。注意:此处GUID和枚举的赋值有问题
                        info.SetValue(t, reader[info.Name] is DBNull ? null : reader[info.Name]);
                    }
                }
            }
        }
        finally
        {
            connection.Close();
        }
        return t;
    }   
}

2、使用参数化---防注入

  正常编写sql语句会导致一个问题,那就是sql注入。意味着,其他编程人员可以未通过你的代码,而是在sql语句后面加上他的sql语句,使得数据库发生了注入操作。因此,参数化数据传入,是防止sql注入的有效方式。

public override T SelectOne<T>(int id)
{
    T t = new T();
    Type type = typeof(T);//获取类型
    string sql = $"select * from [{type.Name}] where [id]=@id";
    try
    {
        connection.Open();
        IDbCommand cmd = connection.CreateCommand();
        cmd.CommandText = sql;
        cmd.Parameters.Add(new SqlParameter("@id", id));
        cmd.CommandType = CommandType.Text;
        IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        if(reader.Read())
        {
            PropertyInfo[] properties = type.GetProperties();
            foreach (var prop in properties)
            {
                if(prop.CanWrite)
                {
                    prop.SetValue(t, reader[prop.Name] is DBNull ? null : reader[prop.Name]);
                }
            }
        }
    }
    finally
    {
        connection.Close();
    }

    return t;
}

3、使用特性标记、反射数据库对象和字段

  前面所有的反射操作,均是基于类名和数据库表名一致、类的属性名和数据库表中的字段一直的情况。那如果不一样呢?又应该如何操作。以前学到了特性,所以这个地方也需要用到特性进行标记。

public override T SelectOne<T>(int id)
{
    T t = new T();
    Type type = typeof(T);
    //应用特性后: 表名与类名,或者属性名与数据库字段名可能不相同,并查询指定的列
    Type attrType = typeof(DbNameAttribute);
    IEnumerable<PropertyInfo> lstPrimaryKey = type.GetProperties().Where(p => p.IsDefined(attrType, true)).Where(p =>
     (p.GetCustomAttribute(attrType) as DbNameAttribute).IsPrimaryKey);
    string primaryKeyName = GetPropertyDBName(lstPrimaryKey.First());
    //使用特性  但不使用参数化
    {
        string sql = string.Format("select {0} from {1} where [{2}]={3}",
              string.Join(",", GetColumnNames(type)), GetTableName(type), primaryKeyName, id);
        try
        {
            connection.Open();

            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            if (reader.Read())
            {
                PropertyInfo[] infos = type.GetProperties();
                foreach (var prop in infos)
                {
                    if (prop.CanWrite)
                    {
                        string dbName = GetPropertyDBName(prop);
                        //设置对应的值。注意:此处GUID和枚举的赋值有问题
                        prop.SetValue(t, reader[dbName] is DBNull ? null : reader[dbName]);
                    }
                }
            }
        }
        finally
        {
            connection.Close();
        }
    }
    //使用特性和参数化
    {
        string sql = string.Format("select {0} from {1} where [{2}]={3}",
              string.Join(",", GetColumnNames(type)), GetTableName(type), primaryKeyName, $"@{primaryKeyName}");
        try
        {
            connection.Open();
            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.Parameters.Add(new SqlParameter($"@{primaryKeyName}", id));
            cmd.CommandType = CommandType.Text;
            IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            if(reader.Read())
            {
                PropertyInfo[] infos = type.GetProperties();
                foreach (var prop in infos)
                {
                    if(prop.CanWrite)
                    {
                        string dbName = GetPropertyDBName(prop);
                        //设置对应的值。注意:此处GUID和枚举的赋值有问题
                        prop.SetValue(t, reader[dbName] is DBNull ? null : reader[dbName]);
                    }
                }
            }
        }
        finally
        {
            connection.Close();
        }
    }

    return t;
}

  反射特性的代码:

/// <summary>
/// 获取表名称
/// </summary>
/// <param name="type">类型</param>
/// <returns>如果有标记就返回标记,如果没有标记则返回类名</returns>
protected string GetTableName(Type type)
{
    Attribute attribute = type.GetCustomAttribute(typeof(DbNameAttribute), true);
    if (attribute != null && attribute is DbNameAttribute)
    {
        string name = (attribute as DbNameAttribute).Name;
        if (string.IsNullOrEmpty(name) == false)
        {
            return name;
        }
    }
    return type.Name;
}

/// <summary>
/// 获实体对应数据库中的列名称
/// </summary>
/// <param name="type">获取的类型</param>
/// <returns>所有被标记的名称和没有被标记的字段名</returns>
protected string[] GetColumnNames(Type type)
{
    PropertyInfo[] propertyInfos = type.GetProperties();
    List<string> names = new List<string>();
    foreach (PropertyInfo property in propertyInfos)
    {
        if (property.CanWrite)//只读取能写入数据的
        {
            names.Add(GetPropertyDBName(property));
        }
    }
    return names.ToArray();
}

/// <summary>
/// 获取属性的数据库名称
/// </summary>
/// <param name="property">属性</param>
/// <returns>数据库名称</returns>
protected string GetPropertyDBName(PropertyInfo property)
{
    string name = string.Empty;
    Attribute attribute = property.GetCustomAttribute(typeof(DbNameAttribute), true);
    if (attribute != null && attribute is DbNameAttribute)
    {
        name = (attribute as DbNameAttribute).Name;
    }
    if (string.IsNullOrEmpty(name))
    {
        return property.Name;
    }
    else
    {
        return name;
    }
}

4、关于其他方法的编写

①直接使用sql语句进行操作

/// <summary>
/// 正常编写sql语句和顺序写代码
/// </summary>
public class SqlHelper //: IDBHelper
{
    /// <summary>
    /// Sql连接
    /// </summary>
    protected SqlConnection connection = new SqlConnection();

    public SqlHelper()
    {
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
        builder.DataSource = @"(LocalDB)\MSSQLLocalDB";
        builder.AttachDBFilename = @"C:\Users\Nigel\Desktop\StudentManage\StudentManage\Database1.mdf";
        builder.IntegratedSecurity = true;
        connection.ConnectionString = builder.ConnectionString;
    }

    /// <summary>
    /// 查询一个对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    public virtual T SelectOne<T>(int id) where T : class, IModel, new()
    {
        T t = new T();

        Type type = typeof(T);
        //没有应用特性的情况:此时,表名与类名相同、属性名和数据库字段名相同
        string sql = $"select * from [{type.Name}] where id = {id}";
        try
        {
            connection.Open();
            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            if (reader.Read())
            {
                PropertyInfo[] infos = type.GetProperties();
                foreach (var info in infos)
                {
                    if (info.CanWrite)
                    {
                        //设置对应的值。注意:此处GUID和枚举的赋值有问题
                        info.SetValue(t, reader[info.Name] is DBNull ? null : reader[info.Name]);
                    }
                }
            }
        }
        finally
        {
            connection.Close();
        }
        return t;
    }

    /// <summary>
    /// 查询所有对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public virtual List<T> SelectAll<T>() where T : class, IModel, new()
    {
        List<T> lstResult = new List<T>();

        Type type = typeof(T);
        //没有应用特性的情况:此时,表名与类名相同、属性名和数据库字段名相同
        string sql = $"select * from [{type.Name}]";
        try
        {
            connection.Open();

            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            PropertyInfo[] infos = type.GetProperties();
            while (reader.Read())
            {
                T t = new T();
                foreach (var info in infos)
                {
                    if (info.CanWrite)
                    {
                        //设置对应的值。注意:此处GUID和枚举的赋值有问题
                        info.SetValue(t, reader[info.Name] is DBNull ? null : reader[info.Name]);
                    }
                }
                lstResult.Add(t);
            }
        }
        finally
        {
            connection.Close();
        }

        return lstResult;
    }


    /// <summary>
    /// 插入一个对象 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t"></param>
    /// <returns></returns>
    public virtual int Insert<T>(T t)
    {
        Type type = typeof(T);
        //获取写入的键值
        Dictionary<string, object> keyValues = new Dictionary<string, object>();
        PropertyInfo[] properties = type.GetProperties();
        for (int i = 0; i < properties.Length; i++)
        {
            if (properties[i].CanWrite)
            {
                keyValues.Add(properties[i].Name, properties[i].GetValue(t));
            }
        }
        string sql = $"insert [{type.Name}]({string.Join(",", keyValues.Keys)}) values('{string.Join("','", keyValues.Values)}')";
        int result = 0;
        //SqlTransaction transaction;
        try
        {
            connection.Open();
            //transaction = connection.BeginTransaction();//事务处理
            IDbCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            result= cmd.ExecuteNonQuery();
            //transaction.Commit();
        }
        catch(Exception ex)
        {
            //transaction.Rollback();
            throw ex;
        }
        finally
        {
            connection.Close();
        }
        return result;
    }

    /// <summary>
    /// 删除数据
    /// </summary>
    /// <typeparam name="T">需要删除的对象</typeparam>
    /// <param name="t"></param>
    /// <returns></returns>
    public virtual int Delete<T>(T t)
    {
        return 0;
    }
    /// <summary>
    /// 删除数据
    /// </summary>
    /// <param name="id">需要删除的id</param>
    /// <returns>受影响行数</returns>
    public virtual int Delete<T>(int id)
    {
        return 0;
    }

    /// <summary>
    /// 删除数据
    /// </summary>
    /// <param name="id">需要删除的id</param>
    /// <param name="t">更新数据</param>
    /// <returns>受影响行数</returns>
    public virtual int Update<T>(T t)
    {
        return 0;
    }
}
View Code

相关文章:

  • 2022-01-07
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-27
  • 2021-11-19
  • 2022-01-06
猜你喜欢
  • 2021-04-10
  • 2021-11-16
  • 2021-06-07
  • 2021-09-08
  • 2022-01-15
  • 2021-11-22
  • 2021-08-24
相关资源
相似解决方案