【问题标题】:LIKE clause issue in c# but works in SQL Server ExpressC# 中的 LIKE 子句问题,但在 SQL Server Express 中有效
【发布时间】:2016-12-08 14:22:33
【问题描述】:

好的,所以我遇到了我的组合框值的问题,它没有根据我正在处理的项目返回我想要的结果。

所以问题是这样的:我想通过组合框中的子字符串进行搜索。澄清一下,我希望组合框中的字符串根据我输入的字符串的任何部分返回必要的值。目前它所做的只是用项目填充组合框。我想要的是在填充组合框后它应该根据我输入的任何字符返回一个字符串。所以假设当我输入“123”或“k”或任何子字符串时我有“stack123”这个词,它会缩小组合框项目并根据输入的子字符串显示值或仅返回单词“stack123”

string query = "SELECT * FROM dbo.Carimed WHERE Item_Description LIKE '%" + comboBox1.Text.Trim().Replace("'", "''") + "%'; "; 

我不知道这是否有帮助,但这是完整的:

using System;
using System.Data.SqlClient;
using System.Windows.Forms;

namespace comboBoxTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            fillCari();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        void fillCari()//fill Cari-med dropdown with values
        {
            try
            {
                string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Carimed_Inventory;Integrated Security=True";
                SqlConnection con2 = new SqlConnection(connectionString);
                con2.Open();
                string query = "SELECT * FROM dbo.Carimed WHERE Item_Description LIKE '%" + comboBox1.Text.Trim().Replace("'", "''") + "%'; "; 
                SqlCommand cmd2 = new SqlCommand(query, con2);

                SqlDataReader dr2 = cmd2.ExecuteReader();

                while (dr2.Read())
                {
                    string cari_des = dr2.GetString(dr2.GetOrdinal("Item_Description"));
                    comboBox1.Items.Add(cari_des);
                }

                con2.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
    }
}

可能是什么问题?

【问题讨论】:

  • 您已经承认您的代码容易受到 SQL 注入攻击,并表示这只是一个练习。但是你真的应该学会总是编写参数化代码。你为什么会错误地练习?您还应该正确处理您的IDisposable 对象,例如SqlConnection。它应该包含在 using 语句中或放置在 finally 块中。
  • 会不会是区分大小写的原因?
  • 当您只访问结果中的一列时,使用SELECT * 是一种不好的做法
  • 我同意@mason。没有理由不编写正确的代码。我们并不挑剔。实际上,只需使用参数化查询,您的问题就有可能消失。
  • 您在表单构造函数中调用此 fillCari。这个组合框 1 的初始值是多少?此时,您没有机会在该组合框中编写任何内容,因此使用的值(如果有)是您在 InitializeComponent 调用中设置的值。为什么要设置用于搜索的相同组合框的项目?

标签: c# sql-server winforms


【解决方案1】:

也许不是

'%" + comboBox1.Text.Trim().Replace("'", "''") + "%' 

您的意思是使用文本框的值?喜欢:

'%" + textBox1.Text.Trim().Replace("'", "''") + "%' 

【讨论】:

  • 否,值必须来自组合框。它是一个基于自动完成接受文本的组合框
  • 仅供参考 @basarab 您使用 tilda 字符来格式化内联代码块,而不是单引号。此外,如果您在自己的行上使用 4 个空格缩进代码,则不需要 tilda 字符。我已建议对您的帖子进行这些更改的修改,但下次通知您。
  • 谢谢,@sab669。我尝试用四个空格缩进代码部分,但我无法让它工作。不知道我做错了什么。
【解决方案2】:

我编辑了我的答案,因为它没有像版主指出的那样提供足够的清晰度,因为我提到的源链接可能会被删除。如果您需要进一步说明,链接将在此说明中。好的,解决方法是使用来自 here 的该用户的指南 作者所做的是覆盖 winforms 中的默认组合框设置。我刚刚找到了一种将它绑定到我的代码中并让它运行起来的方法。希望这对将来的某人有所帮助。我将概述它是如何工作的

suggestComboBox.DataSource = new List<person>();
suggestComboBox.DisplayMember = "Name";

// then you have to set the PropertySelector like this:
suggestComboBox.PropertySelector = collection => collection.Cast<person>      
().Select(p => p.Name);

// the class Person looks something like this:
class Person
{
  public string Name { get; set; }
  public DateTime DateOfBirth { get; set; }
  public int Height { get; set; }
}</person>

这是自定义组合框的实现:

public class SuggestComboBox : ComboBox
{
  #region fields and properties

private readonly ListBox _suggLb = new ListBox { Visible = false, TabStop = false };
private readonly BindingList<string> _suggBindingList = new BindingList<string>();
private Expression<Func<ObjectCollection, IEnumerable<string>>> _propertySelector;
private Func<ObjectCollection, IEnumerable<string>> _propertySelectorCompiled;
private Expression<Func<string, string, bool>> _filterRule;
private Func<string, bool> _filterRuleCompiled;
private Expression<Func<string, string>> _suggestListOrderRule;
private Func<string, string> _suggestListOrderRuleCompiled;

public int SuggestBoxHeight
{
    get { return _suggLb.Height; }
    set { if (value > 0) _suggLb.Height = value; }
}
/// <summary>
/// If the item-type of the ComboBox is not string,
/// you can set here which property should be used
/// </summary>
public Expression<Func<ObjectCollection, IEnumerable<string>>> PropertySelector
{
    get { return _propertySelector; }
set
{
    if (value == null) return;
    _propertySelector = value;
    _propertySelectorCompiled = value.Compile();
}
}

///<summary>
/// Lambda-Expression to determine the suggested items
/// (as Expression here because simple lamda (func) is not serializable)
/// <para>default: case-insensitive contains search</para>
/// <para>1st string: list item</para>
/// <para>2nd string: typed text</para>
///</summary>
public Expression<Func<string, string, bool>> FilterRule
{
    get { return _filterRule; }
    set
    {
        if (value == null) return;
        _filterRule = value;
        _filterRuleCompiled = item => value.Compile()(item, Text);
    }
}

///<summary>
/// Lambda-Expression to order the suggested items
/// (as Expression here because simple lamda (func) is not serializable)
/// <para>default: alphabetic ordering</para>
///</summary>
public Expression<Func<string, string>> SuggestListOrderRule
{
    get { return _suggestListOrderRule; }
    set
    {
        if (value == null) return;
        _suggestListOrderRule = value;
        _suggestListOrderRuleCompiled = value.Compile();
    }
}

#endregion

/// <summary>
/// ctor
/// </summary>
public SuggestComboBox()
{
    // set the standard rules:
    _filterRuleCompiled = s => s.ToLower().Contains(Text.Trim().ToLower());
    _suggestListOrderRuleCompiled = s => s;
    _propertySelectorCompiled = collection => collection.Cast<string>();

    _suggLb.DataSource = _suggBindingList;
    _suggLb.Click += SuggLbOnClick;

    ParentChanged += OnParentChanged;
}

/// <summary>
/// the magic happens here ;-)
/// </summary>
/// <param name="e"></param>
protected override void OnTextChanged(EventArgs e)
{
    base.OnTextChanged(e);

    if (!Focused) return;

    _suggBindingList.Clear();
    _suggBindingList.RaiseListChangedEvents = false;
    _propertySelectorCompiled(Items)
         .Where(_filterRuleCompiled)
         .OrderBy(_suggestListOrderRuleCompiled)
         .ToList()
         .ForEach(_suggBindingList.Add);
    _suggBindingList.RaiseListChangedEvents = true;
    _suggBindingList.ResetBindings();

    _suggLb.Visible = _suggBindingList.Any(); 

    if (_suggBindingList.Count == 1 &&  
                _suggBindingList.Single().Length == Text.Trim().Length)
    {
        Text = _suggBindingList.Single();
        Select(0, Text.Length);
        _suggLb.Visible = false;
    }
}

/// <summary>
/// suggest-ListBox is added to parent control
/// (in ctor parent isn't already assigned)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnParentChanged(object sender, EventArgs e)
{
    Parent.Controls.Add(_suggLb);
    Parent.Controls.SetChildIndex(_suggLb, 0);
    _suggLb.Top = Top + Height - 3;
    _suggLb.Left = Left + 3;
    _suggLb.Width = Width - 20;
    _suggLb.Font = new Font("Segoe UI", 9);
}

protected override void OnLostFocus(EventArgs e)
{
    // _suggLb can only getting focused by clicking (because TabStop is off)
    // --> click-eventhandler 'SuggLbOnClick' is called
    if (!_suggLb.Focused)
        HideSuggBox();
    base.OnLostFocus(e);
}
protected override void OnLocationChanged(EventArgs e)
{
base.OnLocationChanged(e);
_suggLb.Top = Top + Height - 3;
_suggLb.Left = Left + 3;
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
_suggLb.Width = Width - 20;
}

private void SuggLbOnClick(object sender, EventArgs eventArgs)
{
    Text = _suggLb.Text;
    Focus();
}

private void HideSuggBox()
{
    _suggLb.Visible = false;
}

protected override void OnDropDown(EventArgs e)
{
    HideSuggBox();
    base.OnDropDown(e);
}

#region keystroke events

/// <summary>
/// if the suggest-ListBox is visible some keystrokes
/// should behave in a custom way
/// </summary>
/// <param name="e"></param>
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
    if (!_suggLb.Visible)
    {
        base.OnPreviewKeyDown(e);
        return;
    }

    switch (e.KeyCode)
    {
        case Keys.Down:
            if (_suggLb.SelectedIndex < _suggBindingList.Count - 1)
                _suggLb.SelectedIndex++;
            return;
        case Keys.Up:
            if (_suggLb.SelectedIndex > 0)
                _suggLb.SelectedIndex--;
            return;
        case Keys.Enter:
            Text = _suggLb.Text;
        Select(0, Text.Length);
        _suggLb.Visible = false;
            return;
        case Keys.Escape:
            HideSuggBox();
            return;
    }

    base.OnPreviewKeyDown(e);
}

private static readonly Keys[] KeysToHandle  = new[] 
            { Keys.Down, Keys.Up, Keys.Enter, Keys.Escape };
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // the keysstrokes of our interest should not be processed be base class:
    if (_suggLb.Visible && KeysToHandle.Contains(keyData))
        return true;
    return base.ProcessCmdKey(ref msg, keyData);
}

#endregion

}

【讨论】:

  • 虽然这可能已经解决了您的问题(无论是什么问题),但它与您的问题没有任何共同之处,标题和内容仍然具有误导性 - 一个典型的 XY 问题。因此,我看不出它对将来的某人有什么帮助。
  • @IvanStoev 这就是为什么在我的回答中我明确表示这是一个“解决方法”,这意味着可以替代发布的原始问题。换句话说,如果他们从未让“LIKE 子句”起作用,那么他们会将其用作“解决方法”。我不同意它与当前问题无关,它确实,它只是一个“解决方法”。
【解决方案3】:

如果你使用的是framework 4.0或更高版本,那么你可以尝试只在填充数据源之后添加以下行,即在构造函数中的filcari()之后。

comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;

并删除查询中的 where 子句,这就像一个魅力。

【讨论】:

  • 我不想要自动完成。我什至在我的描述中这么说。自动完成仅适用于输入的第一个字符。我想当我输入任何字符/字符时,无论是开头、结尾还是中间,它仍然会拉出我想要的字符串。例如。如果我有“stack123”这个词,然后我输入“123”或“stack”或“k12”,它仍然会拉出“stack123”这个词。请花时间正确阅读原始描述
【解决方案4】:

此示例用于根据提示文本过滤组合项,但当组合框用所选文本覆盖提示时会出现问题。每次您键入另一个字母时,它都会重新填充组合框。

public Form1()
{
    InitializeComponent();
    PopulateCombo(String.Empty);
}

private void comboBox1_KeyUp(object sender, KeyEventArgs e)
{
    var hint = comboBox1.Text;
    PopulateCombo(hint);
}

private void PopulateCombo(string hint)
{
    comboBox1.Items.Clear();
    var connString = @"Server=.\sqlexpress;Database=NORTHWND;Trusted_Connection=True;";
    using(var con2 = new SqlConnection(connString))
    {
        var query = "select CategoryName from Categories where CategoryName like '%' + @HINT + '%'";
        using (SqlCommand cmd2 = new SqlCommand(query, con2))
        {
            cmd2.Parameters.Add("@HINT", SqlDbType.VarChar);
            cmd2.Parameters["@HINT"].Value = hint.Trim();
            con2.Open();
            var dr2 = cmd2.ExecuteReader();
            while (dr2.Read())
            {
                 comboBox1.Items.Add(dr2.GetString(0));
            }
            //reset cursor to end of hint text
            comboBox1.SelectionStart = comboBox1.Text.Length;
            comboBox1.DroppedDown = true;
        }
    }
}

【讨论】:

    【解决方案5】:
    1. 为您的数据创建类型
    2. 创建该类型的列表
    3. 使用数据库中的数据填充列表
    4. 使用 linq 扩展方法对列表进行排序
    5. 将排序列表绑定到组合框
    
        using System;
        using System.Collections.Generic;
        using System.Data;
        using System.Data.SqlClient;
        using System.Linq;
        using System.Drawing;
        using System.Windows.Forms;
        using System.Configuration;
        namespace Combo
        {
          
          class DataItem
          {
            public int Id { get; set; }
            public string Name { get; set; }
          }
          public partial class MainForm : Form
          {
            List<DataItem>dataitems=new List<DataItem>();
            public MainForm()
            {
              
              InitializeComponent();
              textBox1.TextChanged+=textbox1textChanged;
              getDataItems();
              comboBox1.DisplayMember="Name";
              comboBox1.DataSource=dataitems;
                
            }
        
            void textbox1textChanged(object sender, EventArgs e)
            {
              if (!string.IsNullOrWhiteSpace(textBox1.Text))
                    {
                comboBox1.DataSource=dataitems.FindAll(d => d.Name.StartsWith(textBox1.Text));
                    }
            }
            void getDataItems()
                {
                    try
                    {
                        using (
                            SqlConnection connection =
                                new SqlConnection(ConfigurationManager.ConnectionStrings["DataItem"].ConnectionString))
                        {
                            if (connection.State == ConnectionState.Closed)
                            {
                                connection.Open();
                                string query = @"SELECT p.ProductId,p.ProductName FROM Product p";
                                var command = new SqlCommand(query, connection) { CommandType = CommandType.Text };
                                var reader = command.ExecuteReader();
                                while (reader.Read())
                                {
                                  var data=new DataItem();
                                  data.Id=reader.GetInt32(0);
                                  data.Name=reader.GetString(1);
                                  dataitems.Add(data);
                                }
                                connection.Close();
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        MessageBox.Show(exception.Message.ToString(), "Error");
                    }
        
        
                }
          }
          
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多