惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
D
Docker
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Project Zero
Project Zero
Engineering at Meta
Engineering at Meta
J
Java Code Geeks
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Simon Willison's Weblog
Simon Willison's Weblog
S
Security Affairs
NISL@THU
NISL@THU
T
Tor Project blog
A
About on SuperTechFans
宝玉的分享
宝玉的分享
腾讯CDC
S
Schneier on Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
P
Privacy & Cybersecurity Law Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
雷峰网
雷峰网
C
Cyber Attacks, Cyber Crime and Cyber Security
Vercel News
Vercel News
Cisco Talos Blog
Cisco Talos Blog
D
DataBreaches.Net
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
L
LINUX DO - 热门话题
Microsoft Security Blog
Microsoft Security Blog
Latest news
Latest news
C
Check Point Blog
有赞技术团队
有赞技术团队
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
云风的 BLOG
云风的 BLOG
SecWiki News
SecWiki News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
爱范儿
爱范儿
月光博客
月光博客
V
Vulnerabilities – Threatpost
T
Threat Research - Cisco Blogs
P
Palo Alto Networks Blog
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Webroot Blog
Webroot Blog
S
Security @ Cisco Blogs

博客园 - sobaby

Sql Server的两个小技巧 用vue.js重构订单计算页面 用vue.js实现购物车功能 一步步实现自己的ORM(五) 一步步实现自己的ORM(四) 将Object转换成Dictionary方法 一步步实现自己的ORM(三) 一步步实现自己的ORM(二) 修复Windows XP服务扩展视图显示空白 ASP.NET MVC :MVC页面验证与授权 一起学习MVC(4)-entity SQL语句 一起学习MVC(3)-搭建项目 一起学习MVC(2)-数据库设计 一起学习MVC(1)-搭建开发环境 什么是工作流 学习WWF中 关于回调函数 ASP.net:水晶报表的5种表格设计模式 ASP.NET 安全认证(一):如何运用 Form 表单认证
一步步实现自己的ORM(一)
sobaby · 2015-03-16 · via 博客园 - sobaby

 最近在研究ORM,尝试着自己开发了一个简单的ORM。我个人不喜欢EF因为跟不上EF升级太快了,再说公司里还停留在c# 3.5时代,对于NHibernate配置太复杂看到就头晕,就心生自己做一个ORM的念头,现在把开发过程中的点点滴滴记录下来,供自己和新手参考,大神请直接忽略这篇文章。

  ORM(object relation mapping)对象关系映射,常用来映射数据库里表、字段等信息。ORM的原理无非就是用配置文件、Attribute来映射数据关系。我们一步步来来创建ORM,定义一个实体类,然后用反射获得类名(表名)、属性(对应是字段名称),例子如下:

CREATE TABLE [dbo].[User](
    [UserId] [int] NOT NULL primary key,
    [Email] [nvarchar](100) NULL,
    [CreatedTime] [datetime] NULL
)

  在这里我创建一张表,其中UserId是主键,为什么不定义成自增长的呢?请保留这个疑问,继续看下去。表创建好了,下面就是定义一个类,如下:

    public class User
    {
        public int UserId { get; set; }

        public string Email { get; set; }

        public DateTime CreatedTime { get; set; }
    }

现在我们要对这个类写一个INSERT操作,直接传入User对象然后插入到数据库。我们要用系统自动构建SQL语句,不需要手写SQL语句,在这我们先分析下INSERT INTO SQL语句。

INSERT INTO 表名
           (字段1
           ,字段2
           ,字段3...)
     VALUES
           值1,
           值2,
           值3...

我们需要知道表名、字段名和值才能够完成SQL拼接,怎么得到这些信息呢,万能的反射该出场。 

            string className = typeof(User).Name;
            Console.WriteLine("类名:{0}", className);
            Console.WriteLine("-----获取属性信息-----");
            var properties = typeof(User).GetProperties();
            foreach (var item in properties)
            {
                Console.WriteLine("属性名:{0}",item.Name);
            }
            Console.WriteLine("-----end-----");

运行结果如下

LOOK,User类的信息都显示出来了,属性的值该如何显示?也就是SQL语句的VALUE,还是要靠万能的反射,请看官门继续往下看。

            string className = typeof(User).Name;
            Console.WriteLine("类名:{0}", className);
            var properties = typeof(User).GetProperties();
            User user = new User() { 
                 UserId = 123,
                  Email = "abc@123.com",
                   CreatedTime = DateTime.Now
            };

            foreach (var item in properties)
            {
                Console.WriteLine("{0}:{1}", item.Name, item.GetValue(user, null));
            }

类名、属性名、属性值我们都得到了,那下面要做的就是拼写SQL语句了

        public static void Main()
        {
            PritSql(new User()
            {
                UserId = 123,
                Email = "abc@123.com",
                CreatedTime = DateTime.Now
            });

        }

        public static void PritSql(User user)
        {

            string className = typeof(User).Name;
            var properties = typeof(User).GetProperties();

            StringBuilder sql = new StringBuilder();
            sql.Append("INSERT INTO ").Append(className).Append("(");

            for (int i = 0; i < properties.Length; i++)
            {
                var pi = properties[i];
                if (i > 0)
                    sql.Append(",");
                sql.Append(pi.Name);
            }
            sql.Append(") VALUES (");
            for (int i = 0; i < properties.Length; i++)
            {
                var pi = properties[i];
                if (i > 0)
                    sql.Append(",");
                sql.Append("'").Append(pi.GetValue(user,null)).Append("'");
            }
            sql.Append(")");
            Console.WriteLine(sql);

        }

View Code

 为避免SQL注入,我把SQL改成参数的信息

INSERT INTO 表名
           (字段1
           ,字段2
           ,字段3...)
     VALUES
           @p1,
           @p2,
           @p3...

修改后的c#代码

    public static void Main()
        {
            PritParameterSql(new User()
            {
                UserId = 123,
                Email = "abc@123.com",
                CreatedTime = DateTime.Now
            });

        }
        public static int PritParameterSql<T>(T user)
        {
            Dictionary<string, object> parameters = new Dictionary<string, object>();
            string className = typeof(T).Name;
            var properties = typeof(T).GetProperties();

            StringBuilder sql = new StringBuilder();
            sql.Append("INSERT INTO [").Append(className).Append("](");

            for (int i = 0; i < properties.Length; i++)
            {
                var pi = properties[i];
                if (i > 0)
                    sql.Append(",");
                sql.Append(pi.Name);
            }
            sql.Append(") VALUES (");
            for (int i = 0; i < properties.Length; i++)
            {
                var pi = properties[i];
                if (i > 0)
                    sql.Append(",");
                sql.Append("@p").Append(i);

                parameters.Add("@p" + i, pi.GetValue(user, null));
            }
            sql.Append(")");
            Console.WriteLine(sql);

            SqlConnection conn = new SqlConnection(connectionString);
            var cmd = conn.CreateCommand();
            cmd.CommandText = sql.ToString();
            foreach (var item in parameters)
            {
                var pa = cmd.CreateParameter();
                pa.ParameterName = item.Key;
                pa.Value = item.Value ?? DBNull.Value;
                cmd.Parameters.Add(pa);
            }


            conn.Open();
            return cmd.ExecuteNonQuery();
        }

View Code

执行后的结果

还记得前面提到为什么UserId不设置成自增长吗?因为这种单纯的反射无法识别哪个是自增长字段,如果想用自增长主键怎么办?请看后续文章。