ORM框架学习(二)

ORM框架--新增数据

今天的内容对照上一节内容,上一节内容是对数据的查询,本节主要是对数据的新增。程序入口代码如下

static void Main(string[] args)
        {
            SqlHelper help = new SqlHelper();
            UserModel u1 = help.Query<UserModel>(1);
            Company com1 = help.Query<Company>(2);
            bool re1 = help.AddData(u1);
            bool re2 = help.AddData(com1);
        }

AddData()方法和Query()方法一样。都是限制为where T:BaseModel的泛型方法。AddData代码如下所示

 public bool AddData<T>(T t) where T:BaseModel
        {
            bool re = true;
            
            try
            {
                Type type=typeof(T);
                string conStr = "Server=127.0.0.1;Database=master; integrated security=SSPI";
                string AddStr = SqlBuilder<T>.GetSql(SqlBuilder<T>.SqlType.AddSql);
                var sqlpara = type.GetProperties().FilterKey().Select(p => new SqlParameter("@" + p.GetMappingName(), p.GetValue(t) ?? DBNull.Value)).ToArray();
                using (SqlConnection conn = new SqlConnection(conStr))
                {
                    SqlCommand cmd = new SqlCommand(AddStr, conn);
                    cmd.Parameters.AddRange(sqlpara);
                    conn.Open();
                    int result= cmd.ExecuteNonQuery();
                    return result > 0;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
                re = false;
            }
            return re;
        }

1.按照特性过滤不需要实体字段

因为我们现在做的是新增,数据库设计id为自增类型,所以在insert时,我们不需要新增id字段,所以就要想办法把id字段过滤。解决的办法是通过给ID设置特性ThemeKeyAttribute,特性定义如下所示

/// <summary>
    /// 主键特性
    /// </summary>
    public class ThemeKeyAttribute:Attribute
    {
    
    }

在特性方法里面没有任何实现,主要目的是用来做标记。同时,我们需要为id字段添加上面定义的特性,如下所示

public class BaseModel
    {
        [ThemeKeyAttribute]
        public int Id { get; set; }
    }

这样一来,就把company实体和User尸体的ID字段加上了特性。我们需要在获取实体属性时,调用过滤主键方法

Filter是一个IEnumerable类型那个的扩展方法,定义如下所示:

public static IEnumerable<PropertyInfo> FilterKey(this IEnumerable<PropertyInfo> props)
        {
            return props.Where(p=>!p.IsDefined(typeof(ThemeKeyAttribute),true));
        }

在Filter方法中,直接传入当前的属性集合类型,把标记有ThemeKeyAttribute的属性过滤掉后再返回集合。

在Filter方法中,我们通过方法p.IsDefined(typeof(ThemeKeyAttribute),true)就可以判断一个类型是否具有某种特性。

2.泛型缓存

由于在执行AddData()方法时,我们的sql语句结构都是类似的(insert into [tab]([]) values('')),为了提高代码执行效率,避免每次执行AddData()方法都去初始化一次sql语句,我们决定采用泛型缓存的方法,定义如下一个泛型类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Theme.Model;
using Theme.Framework;
namespace Theme.DAL
{
    public  class SqlBuilder<T> where T:BaseModel
    {
        private static string FindSql=null;
        private static string AddSql=null;
        static SqlBuilder()
        {
            {
                Type t = typeof(T);
                string table = t.GetMappingName();
                string props = string.Join(",", t.GetProperties().Select(p => "[" + p.GetMappingName() + "]"));
                T ti = Activator.CreateInstance<T>();
                FindSql = string.Format("select {0} from [{1}] where id=@id ", props, table);
            }
            {
                Type type = typeof(T);
                string table = type.GetMappingName();
                string param = string.Join(",", type.GetProperties().FilterKey().Select(p => "[" + p.GetMappingName() + "]"));
                string valueStr = string.Join(",", type.GetProperties().FilterKey().Select(p => "@" + p.GetMappingName()));
                
                //id为自增的关键字,不能插入,应该把ID屏蔽
                AddSql = string.Format("insert into [{0}]({1}) values({2})", table, param, valueStr);
            }
        }
        public static string GetSql(SqlType sqltype)
        {
            switch (sqltype)
            {
                case SqlType.AddSql:
                    return AddSql;
                case SqlType.FindSql:
                    return FindSql;
                default:
                    throw new Exception("wrong sqlType");
            }
        }
        public enum SqlType
        {
            FindSql,
            AddSql
        }
    }
}

注意,要通过限制当前类只能是继承了BaseModel父类的才能访问。我们把sql语句定义成静态字段,在每次使用该类之前,该类进行初始化生成FindSql和AddSql语句。这样确保了一个类型的对象只会初始化一次sql语句,这样就节省了多对象调用反复拼装sql语句的问题。

3.参数化sql,避免sql注入

为了避免SQL注入问题的发生,我们通过参数化的方法拼装SQL执行语句,如下图所示:

 在具体执行sql语句时,添加一下各个参数的值,如下图所示:

原文地址:https://www.cnblogs.com/zxwDont/p/11473874.html