将字符串数据保存到包含单引号的SQL Server的最佳方法是什么

时间:2017-05-18 11:18:31

标签: c# sql-server string

我有一个C#程序需要处理数据并将其存储在SQL Server中。我遇到的问题是合法保存的一些数据包含单引号。保存数据时,我需要找到包含单引号的项目,并主动用单引号替换单引号,这样我就不会得到截断的字符串。

目前,无论我在添加可能包含单引号的数据,我都会通过以下例程将其传递给一个名为FSQ的静态模块(修复单引号),这是例程:

/// <summary>
/// Fix Single Quote - Used to remove Double quotes from strings that would confuse Access database by replacing with Single Quotes.
/// </summary>
/// <param name="s">String text to be fixed by removing double quotes.</param>
/// <returns>The original string with any double-quotes removed and replaced with single quotes. If an error occurs will return an empty string.</returns>
public static string FSQ(string s)
{
    string tmp ="";

    try
    {
        if (s == null)
            return "";

        s = s.Trim();

        if (s == "")
            return s;

        if(s.Contains("'"))
        {
            if(!s.Contains("''"))//Already been fixed previously so skip here
                tmp = s.Replace("'", "''");

                s = tmp;
        }

        return s;


    }
    catch (Exception ex)
    {
        PEH("FDQ", "Common Module", ex.Message);
        return "";
    }
} //public static String FDQ(String s)

这很有效,我的字符串可以保存到SQL,但因为对这个例程有很多调用,所以当程序在处理过程中循环遍历数千行数据时,性能会很糟糕。

是否有一个更有效的例程会否定调用此函数的需要?大多数情况下,我只是构建包含这些项的更新或插入查询。

任何帮助表示感谢。

6 个答案:

答案 0 :(得分:2)

永远不要尝试在代码中构建SQL语句。从来没有尝试过自己逃避的事情。你得到100%可攻击的代码(sql注入)。

根据您使用的数据库适配器,您可以使用参数化查询。

以下是使用ado.net的示例:

var Query = "select * from customers where city = @city";
var cmd = new SqlCommand(Query);
cmd.Parameters.AddWithValue("@city", txtCity);

查询中的@city将是占位符,稍后将在驱动程序级别替换。

答案 1 :(得分:0)

如果您将它作为varchar / nvarchar参数传递给sql server,则不会有任何问题。您无需替换'to''。

答案 2 :(得分:0)

在处理字符串数据时,由于SQL注入攻击,您应该非常警惕如何在SQL Server中处理它。 SQL注入攻击是指攻击者输入格式错误的文本而导致恶意执行数据库中的SQL语句的攻击。<​​/ p>

假设您有一个产品表,以下是您可能编写的用于处理的查询

var query = "SELECT * FROM Products WHERE ProductDesc = " + txtProductDesc;

作为攻击者,我可以输入“智能手机OR 1 = 1”,您可以看到查询最终会列出产品表中的所有产品。

您可以遵循各种消毒技术来避免此类攻击,您可能希望将其用于处理此类攻击

SQL Injection Prevention Cheat Sheet

答案 3 :(得分:0)

您需要做的第一件事是使用依赖注入将处理代码与持久性分离 之后,您处理的数据将作为System.String公开,并由任何DBMS通过适当的接口使用 然后,假设您确实希望坚持使用SQL Server。您可能会使用实体框架,它将依次处理转义字符,因为它具体知道它将存储该数据的位置(字符串类型)...我想至少。这就是我要做的!如果比我更有经验的人认为这是错误的方法,请随时纠正我!

答案 4 :(得分:0)

以下是关于使用参数的前回复,而不是尝试编写自己的方法来处理操作中的撇号,无论是INSERT,DELETE还是UPDATE。以下是很简单的,通过参数添加新记录并返回新的主键。

第一个插入物有一个撇号,第二个插入物有三个撇号。下面的类在一个类项目中,而表单的第二个代码块在一个引用类项目的表单项目中。

using System;
using System.Data.OleDb;
using System.IO;

namespace DataLib
{
    public class Operations1
    {
        public Exception InsertException { get; set; }
        private OleDbConnectionStringBuilder Builder = new OleDbConnectionStringBuilder
        {
            Provider = "Microsoft.ACE.OLEDB.12.0",
            DataSource = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb")
        };
        public Operations1()
        {
            if (!(File.Exists(Builder.DataSource)))
            {
                throw new FileNotFoundException("Failed to find application's database");
            }
        }
        public bool AddNewRow(string CompanyName, string ContactName, ref int Identfier)
        {

            bool success = true;
            int affected = 0;

            try
            {
                using (OleDbConnection cn = new OleDbConnection { ConnectionString = Builder.ConnectionString })
                {
                    using (OleDbCommand cmd = new OleDbCommand { Connection = cn })
                    {
                        cmd.CommandText = @"INSERT INTO Customer (CompanyName,ContactName) 
                            VALUES (@CompanyName, @ContactName)";

                        cmd.Parameters.AddWithValue("@CompanyName", CompanyName);
                        cmd.Parameters.AddWithValue("@ContactName", ContactName);

                        cn.Open();

                        affected = cmd.ExecuteNonQuery();
                        if (affected == 1)
                        {
                            cmd.CommandText = "Select @@Identity";
                            Identfier = Convert.ToInt32(cmd.ExecuteScalar());
                            success = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                InsertException = ex;
                success = false;
            }
            return success;
        }
    }
}

表单代码(模拟/静态数据)

using DataLib;
using System;
using System.Windows.Forms;

namespace DataLibDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Operations1 ops = new Operations1();
            int newIdentifier = 0;
            if (ops.AddNewRow("O'brien and company", "Mary O'brien", ref newIdentifier))
            {
                MessageBox.Show($"New Id for Mary {newIdentifier}");
            }
            else
            {
                MessageBox.Show($"Insert failed: {ops.InsertException.Message}");
            }

            if (ops.AddNewRow("O'''brien and company", "Mary O'brien", ref newIdentifier))
            {
                MessageBox.Show($"New Id for Mary {newIdentifier}");
            }
            else
            {
                MessageBox.Show($"Insert failed: {ops.InsertException.Message}");
            }
        }
    }
}

enter image description here

答案 5 :(得分:-1)

这是您可以实现的最快方式。

public static string FSQ(string s)
{
       try
    {
        s = s.Trim();
        return s = (s != null && s != "")?(s.Contains("'") && !s.Contains("''"))?s.Replace("'", "''"): s:"";

    }
    catch (Exception ex)
    {
        PEH("FDQ", "Common Module", ex.Message);
        return "";
    }
}