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

推荐订阅源

博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
G
Google Developers Blog
B
Blog
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 叶小钗
The Cloudflare Blog
The Hacker News
The Hacker News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
雷峰网
雷峰网
F
Fortinet All Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
A
About on SuperTechFans
量子位
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
H
Help Net Security
Help Net Security
Help Net Security
P
Palo Alto Networks Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Troy Hunt's Blog
W
WeLiveSecurity
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
Know Your Adversary
Know Your Adversary
Apple Machine Learning Research
Apple Machine Learning Research
Scott Helme
Scott Helme
N
News | PayPal Newsroom
AWS News Blog
AWS News Blog
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
B
Blog RSS Feed
腾讯CDC
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
TaoSecurity Blog
TaoSecurity Blog
GbyAI
GbyAI
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker

博客园 - 程序员海风

cef加载flash的办法 一个高性能的对象属性复制类,支持不同类型对象间复制,支持Nullable<T>类型属性 php检测php.ini是否配制正确 openwrt的路由器重置root密码 windows 7 + vs2010 sp1编译 x64位版qt4 解决SourceGrid在某些系统上无法用鼠标滚轮滚动的问题 判断一个点是否在多边形内部,射线法思路,C#实现 [转载]使用HttpWebRequest进行请求时发生错误:基础连接已关闭,发送时发生错误处理 通过WMI - Win32_Processor - ProcessorId获取到的并不是CPU的序列号,也并不唯一 DataGridView中设置固定行高 csExWB Webbrowser禁止flash内容的显示 使用csExWB Webbrowser 控件获取HttpOnly的cookie 禁用IIS FTP默认的连接提示信息:“220-Microsoft FTP Service” C#使用RSA私钥加密公钥解密的改进,解决特定情况下解密后出现乱码的问题 在ASP.NET的单次请求中使用Singleton模式 Windows7的KB2488113补丁很重要,解决Windows7下软件无响应的问题 OpenFileDialog和SaveFileDialog使用不当会有文件夹共享冲突的问题 Cache-Control:nocache 会导致ie浏览器无法保存正确的图片类型 安装阿里旺旺2008会导致IE Webcontrols在客户端显示不正常
让Dapper+SqlCE支持ntext数据类型和超过4000字符的存储
程序员海风 · 2014-10-22 · via 博客园 - 程序员海风

使用Dapper和SqlCE进行开发的时候,如果数据库的某字段是采用的ntext数据类型,并且在这个字段存储的数据超过了4000个字符,会报如下的错误:

Invalid parameter Size value '-1'. The value must be greater than or equal to 0.

在Google上以“dapper sqlce ntext”作为关键词搜索,可以找到如下两个解决办法:

1. Inserting a string larger then 4000 characters using Sql CE 4.0

2. Attempting to Modify Dapper to Support SQL Server CE's ntext type

这两个解决办法,要么通用性较差,要么使用比较麻烦。

通过查看Dapper的源码,发现Dapper在构造参数的动态方法中针对实体类属性为DbString的类型和数据类型为DbType.Xml进行了特别处理,我们也可以在这里入手,针对长字符串进行特别处理。

解决办法:

一、新建一个Attribute,用来标记需要特别处理的实体类属性;

    [AttributeUsage(AttributeTargets.Property)]
    public class LongStringAttribute : Attribute
    {
    }

二、新建一个类,用来处理添加NText类型参数;

    public class LongString
    {

        public static void AddParameter(IDbCommand command, string name, string value)
        {
            var param = command.CreateParameter();
            param.ParameterName = name;
            param.Value = (object)value ?? DBNull.Value;
            param.DbType = DbType.String;

            int length = -1;
            if (!string.IsNullOrEmpty(value))
                length = value.Length;
            if (length == -1 && value != null && value.Length <= 4000)
            {
                param.Size = 4000;
            }
            else
            {
                param.Size = length;
            }
            
            if (value != null)
            {
                if (length > 4000 && param.GetType().Name == "SqlCeParameter")
                {
                    param.GetType().GetProperty("SqlDbType").SetValue(param, SqlDbType.NText, null);
                    param.Size = length;
                }
            }

            command.Parameters.Add(param);
        }

    }

三、修改Dapper的源码,在SqlMapper.CreateParamInfoGenerator方法中,找到以下代码

          if (prop.PropertyType == typeof(DbString))
                {
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param]
                    il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [dbstring]
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [dbstring] [command]
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [dbstring] [command] [name]
                    il.EmitCall(OpCodes.Callvirt, typeof(DbString).GetMethod("AddParameter"), null); // stack is now [parameters]
                    continue;
                }


                //我们的代码插入到这里


                DbType dbType = LookupDbType(prop.PropertyType, prop.Name);
                if (dbType == DbType.Xml)
                {
                    // this actually represents special handling for list types;
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param]
                    il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]
                    if (prop.PropertyType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [command] [name] [boxed-value]
                    }
                    il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("PackListParameters"), null); // stack is [parameters]
                    continue;
                }

修改之后的代码如下:

if (prop.PropertyType == typeof(DbString))
                {
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param]
                    il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [dbstring]
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [dbstring] [command]
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [dbstring] [command] [name]
                    il.EmitCall(OpCodes.Callvirt, typeof(DbString).GetMethod("AddParameter"), null); // stack is now [parameters]
                    continue;
                }

                //这里插入修改的代码
                Attribute lStrAttr = Attribute.GetCustomAttribute(prop, typeof(LongStringAttribute));
                if (lStrAttr != null)
                {
                    //special handling for long string
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param]
                    il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [command] [name] [string]

                    il.EmitCall(OpCodes.Call, typeof(LongString).GetMethod("AddParameter"), null);
                    continue;
                }

                DbType dbType = LookupDbType(prop.PropertyType, prop.Name);
                if (dbType == DbType.Xml)
                {
                    // this actually represents special handling for list types;
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param]
                    il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]
                    if (prop.PropertyType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [command] [name] [boxed-value]
                    }
                    il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("PackListParameters"), null); // stack is [parameters]
                    continue;
                }

这样就可以了,使用的时候,如果我们数据表的某字段是ntext类型,那么我们只需要在定义相应实体类的时候,给相应属性加上LongStringAttribute,Dapper就可以自动识别这个字段,插入正确的数据了。

使用代码如下:

//实体类定义
using System;
using Dapper;

namespace Entity
{
    public class product
    {
        public int Id { get; set; }
        public int shopid { get; set; }
        public string type { get; set; }
        public string outid { get; set; }
        public string link { get; set; }
        public string title { get; set; }
        [LongString]
        public string content { get; set; }
        public decimal price { get; set; }
        public int amount { get; set; }
    }
}


//调用

            product p = new product();
            p.shopid = 1;
            p.title = "梁振英:\"占中\"者不要试探北京忍耐底线";
            p.link = "http://news.163.com/14/1021/13/A936JGST0001124J.html";
            string str = FileHelper.ReadTextFile("content.txt");
            p.content = str;
            p.type = "netease";
            p.outid = "A936JGST0001124J";
            p.price = 123.45M;
            p.amount = 999;

            SqlCeConnection conn = new SqlCeConnection("Data Source=test.sdf");
            conn.Open();

            string sql = "insert into products(shopid,type,outid,link,title,content,price,amount) values(@shopid,@type,@outid,@link,@title,@content,@price,@amount)";
            SqlMapper.Execute(conn, sql, p);

            conn.Close();

我使用的Dapper版本是博客园里@wushilonng改写的针对.NET 2.0的版本,未知最新版Dapper是否针对这方面做了改进。

------全文完-----