static void Main(string[] args)
        {
            //new EmitShow().EmitSayHello();

            var connectionString = "Server=.;Database=dapper;UID=sa;PWD=123456;";

            using (IDbConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                var result      = connection.Query <User>("select 1 Id,N'jack' Name,27 Age").First();
                var resultCatch = connection.Query <User>("select 1 Id,N'jack' Name,27 Age").First();
                //Query Multi Mapping
                var orderuser = connection.Query <Order, User, Order>(@"select * from [Order] t1
                                            left join [User] t2 on t2.Id = t1.UserId",
                                                                      (order, user) =>
                {
                    order.User = user;
                    return(order);
                });
                //14.dynamic Multi Mapping
                var dynamic = connection.Query <dynamic, dynamic, dynamic>(@"select * from [Order] t1
                                            left join [User] t2 on t2.Id = t1.UserId",
                                                                           (post, user) =>
                {
                    post.Owner = user;
                    return(post);
                });
                //SplitOn区分类别Mapping组别
                //假如主键名称是其他名称,请指定splitOn字串名称,并且对应多个可以使用,做区隔,举例,添加商品表格做Join
                //从查询字段从后往前分割,分别赋值给不同的类,主键是Id可以省略
                var orderuserproduct = connection.Query <Order, User, Product, Order>(@"select * from [Order] t1
                                            left join [User] t2 on t2.Id = t1.UserId
                                            left join [Product] t3 on t3.Id=t1.ProductId",
                                                                                      map: (order, user, product) =>
                {
                    order.User    = user;
                    order.Product = product;
                    return(order);
                },
                                                                                      splitOn: "Id,Id");

                //15.使用QueryMultiple优点:
                //主要减少Reqeust次数
                //可以将多个查询共用同一组Parameter参数

                //QueryMultiple的底层实作逻辑:
                //底层技术是ADO.NET - DataReader - MultipleResult
                //QueryMultiple取得DataReader并封装进GridReader
                //呼叫Read方法时才会建立Mapping动态方法, Emit IL动作跟Query方法一样
                //接着使用ADO.NET技术呼叫DataReader NextResult取得下一组查询结果
                //假如没有下一组查询结果才会将DataReader释放
                using (var gridReader = connection.QueryMultiple("select 1; select 2;"))
                {
                    Console.WriteLine(gridReader.Read <int>()); //result : 1
                    Console.WriteLine(gridReader.Read <int>()); //result : 2
                }

                //16.TypeHandler 自订Mapping逻辑使用、底层逻辑
                //User资料变更时会自动在Log栏位纪录变更动作
                SqlMapper.AddTypeHandler(new JsonTypeHandler <List <Log> >());
                var user = new User()
                {
                    Name = "暐翰",
                    Age  = 26,
                    Logs = new List <Log>()
                    {
                        new Log()
                        {
                            Time   = DateTime.Now,
                            Remark = "CreateUser"
                        }
                    }
                };
                //新增用户
                connection.Execute("insert into [User] (Name,Age,Logs) values (@Name,@Age,@Logs);", user);

                var userlogs = connection.Query <User>("select * from [User]");
                Console.WriteLine(userlogs);

                //17.CommandBehavior的细节处理
                //会遇到select top 1知道只会读取一行资料的情况,这时候可以使用
                //QueryFirst。它使用CommandBehavior.SingleRow可以避免浪费资源只读取一行资料

                //与QuerySingle之间的差别
                //两者差别在QuerySingle没有使用CommandBehavior.SingleRow,至于为何没有使用,是因为需要有多行资料才能判断是否不符合条件并抛出Exception告知使用者

                //18.Parameter 参数化底层原理GetCacheInfo检查是否缓存内有动态方法 > 假如没有缓存,使用CreateParamInfoGenerator方法Emit IL建立AddParameter动态方法 > 建立完后保存在缓存内 > 忽略「没使用的栏位」不生成对应IL代码,避免资源浪费情况
                //虽然传递Age参数,但是SQL字串没有用到,Dapper不会去生成该栏位的SetParameter动作IL

                //19.IN 多集合参数化底层原理
                //以下用sys.objects来查SQL Server的表格跟视图当追踪例子 :
                //var result = cn.Query(@"select * from sys.objects where type_desc In @type_descs", new { type_descs = new[] { "USER_TABLE", "VIEW" } });
                //Dapper会将SQL字串改成以下方式执行
                //select* from sys.objects where type_desc In(@type_descs1, @type_descs2)
                //--@type_descs1 = nvarchar(4000) - 'USER_TABLE'
                //-- @type_descs2 = nvarchar(4000) - 'VIEW'

                //20.DynamicParameter 底层原理、自订实作
                var paramter = new
                {
                    Name = "John",
                    Age  = 25
                };
                //String型态Dapper会自动将转成数据库Nvarchar并且长度为4000的参数
                var dynamic1 = connection.Query("select @Name Name,@Age Age", paramter).First();
                //实际执行过程如下
                //exec sp_executesql N'select @Name Name,@Age Age',N'@Name nvarchar(4000),@Age int',@Name=N'John',@Age=25
                var paramters = new DynamicParameters();
                paramters.Add("Name", "John", DbType.AnsiString, size: 4);
                paramters.Add("Age", 25, DbType.Int32);
                var dynamic2 = connection.Query("select @Name Name,@Age Age", paramters).First();

                //预设的实作类别DynamicParameters判断比较多,效率会较慢
                var customPraameters = new CustomPraameters();
                paramters.Add("Name", "John", DbType.AnsiString, size: 4);
                paramters.Add("Age", 25, DbType.Int32);
                var dynamic3 = connection.Query("select @Name Name,@Age Age", paramters).First();

                //21. 单次、多次 Execute 底层原理
                //单次执行,来说Dapper Execute底层是ADO.NET的ExecuteNonQuery的封装,封装目的为了跟Dapper的Parameter、缓存功能搭配使用
                //多次执行,共用资源避免浪费(e.g共用同一个DbCommand、Func),但遇到大量执行追求效率需求情况,需要特别注意
                //此方法每跑一次对数据库送出一次reqesut,效率会被网路传输拖慢
                //所以这功能被称为「多次执行」而不是「批量执行」的主要原因
                using (var tx = connection.BeginTransaction())
                {
                    connection.Execute("create table #T (V int);", transaction: tx);
                    //简化了集合操作Execute之间的操作,简化了代码,只需要 : connection.Execute("sql",集合参数);
                    connection.Execute("insert into #T (V) values (@V)", Enumerable.Range(1, 10).Select(val => new { V = val }).ToArray(), transaction: tx);

                    var dynamics = connection.Query("select * from #T", transaction: tx);
                    Console.WriteLine(result);
                }

                //22.ExecuteScalar应用
                //ExecuteScalar因为其只能读取第一组结果、第一笔列、第一笔资料特性,「查询资料是否存在」还是有用的
                //Entity Framwork如何高效率判断资料是否存在?使用Any而不是Count() > 1
                //Any语法转换SQL使用EXISTS,它只在乎是否有没有资料,不用检查到每列,只需要其中一笔就有结果,所以效率快
                var existsUser = connection.Any("select top 1 1 from [User]");

                Console.WriteLine(result.Name);
            }
            Console.WriteLine("Hello World!");
        }