【问题标题】:Autocomplete Search List issue自动完成搜索列表问题
【发布时间】:2011-12-23 23:00:28
【问题描述】:

我目前正在开发一个具有自动完成搜索表单的网络应用程序,结果正在从 Sql 数据库更新。除了一件事,整个“功能”都在工作。客户端正在调用一个 C# Web 服务,该服务将向客户端返回一个数组。事情是。客户端列表多次显示相同的结果。因此,如果数据库中只有一个匹配项,则客户端会在垂直列表中显示该匹配项 20-25 次。我不知道如何解决这个问题,请帮忙。

C# 网络服务:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Data.SqlClient;

namespace WebApplication6
{

public class searchResult
{
    public string Title;
    public string img;
    public string href;
}

/// <summary>
/// Summary description for WebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(searchResult))]
public class WebService : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }

    [WebMethod]
    public searchResult[] Search(string txtSearch)
    {
        //Semuler to slow internet connection
        //System.Threading.Thread.Sleep(2000);

        //Declare collection of searchResult
        List<searchResult> resultList = new List<searchResult>();

        string constr = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; ;
        SqlConnection con = new SqlConnection(constr);
        SqlCommand cmd = con.CreateCommand();

        cmd.CommandText = "SELECT * FROM [DriverInfo], [Teams], [Tracks] WHERE UserName LIKE '" + txtSearch + "%' OR TeamName LIKE '" + txtSearch + "%' OR TrackName LIKE '" + txtSearch + "%'";
        try
        {
            con.Open();

            SqlDataReader dr = cmd.ExecuteReader();
            while (dr.Read())
            {
                searchResult DriverResult = new searchResult();
                DriverResult.Title = dr["UserName"].ToString();
                DriverResult.img = "driver.png";
                DriverResult.href = dr["UserId"].ToString();

                if (DriverResult.Title.ToLower().Contains(txtSearch.ToLower()))
                {
                    resultList.Add(DriverResult);
                }

                searchResult TeamResult = new searchResult();
                TeamResult.Title = dr["TeamName"].ToString();
                TeamResult.img = "team.png";
                TeamResult.href = dr["Id"].ToString();

                if (TeamResult.Title.ToLower().Contains(txtSearch.ToLower()))
                {
                    resultList.Add(TeamResult);
                }

                searchResult TrackResult = new searchResult();
                TrackResult.Title = dr["TrackName"].ToString();
                TrackResult.img = "track.png";
                TrackResult.href = dr["TrackId"].ToString();

                if (TrackResult.Title.ToLower().Contains(txtSearch.ToLower()))
                {
                    resultList.Add(TrackResult);
                }
            }
            con.Close();
            return resultList.ToArray();
        }
        catch
        {
            return null;
        }

    }
}
  }

HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="http://code.jquery.com/jquery-1.4.3.min.js" type="text/javascript></script>
<link href="main.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
        function search() {
        if ($("#txtSearch").val() != "") {

        $(".divResult").show(); //show div block that contains on result
        $(".loading").show(); // show loading text while getting result

    //call web searvice
            $.ajax({ type: "POST",
                url: "WebService.asmx/Search", //function that in web service
                data: "{txtSearch:'" + $("#txtSearch").val() + "'}",// passing value of txtSearch input
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function(response) {
        //declaer client object and set to it returned result from web sevice function
                    var result = response.d;
                    $(".record").html(""); // clear previous result

        //looping in 'result' array to get data and fill it inside ".record" div as html
                    $.each(result, function(index, res) {

            //append img tag inside ".record" div
                        $('<img />', {
                            src: 'Images/' + res.img,
                            alt: res.Title
                        }).addClass("img").appendTo('.record');

            //append anchor tag inside ".record" div
                        $('<a></a>', {
                            href: res.href,
                            text: res.Title
                        }).addClass("txtResult").appendTo('.record');

                        $(".record").append("<hr />");
                    });
        //hide loading div when the data was got
                    $(".loading").hide();
                },
                error: function(msg) {
                    $(".record").html(msg.d);
                }

            });

        }
        else {
        $(".divResult").hide(); //hide div that contains result when the input text is empty
        $(".record").html(""); //also loading text when the input text is empty
        }
    }
</script>
</head>
<body>
<div class="content">
    <input id="txtSearch" onkeyup="search()" type="text" />
<div class="divResult">
<div class="loading">Loading..</div>
<div class="record"></div>
</div>
</div>
</body>
</html>

CSS:

        .content
    {
        margin:50px auto;
        text-align:center;
        width:322px;
    }

    #txtSearch
    {
        border:solid 1px #cccccc;
        width:320px;
        color:#555555;
        font: 18pt tahoma;
        height: 20px;
        font-size: 12px;
        font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
    }
    .divResult
    {
        position:absolute;
        background-color:#F2F2FF;
        border-style:solid;
        border-width:1px;
        border-color:#999999;
        width:320px;
        text-align:left;
        display:none;
    }
    .img
    {
        padding-top: 2px;
        width:30px;
        height:30px;
        float:left;
    }
    .txtResult
    {
        display:block;
        width:320px;
        height:30px;
        color:#3c5899;
        font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
        font-size: 14px;
        font-weight: bold;
        text-decoration:none;
    }
    .txtResult:hover {
        background-color: #3c5899;
        color: White;
    }
    .loading
    {
        font: 10pt tahoma;
        text-align:center;
    }
    .record
    {
        margin:0px;
    }

【问题讨论】:

    标签: c# javascript asp.net html css


    【解决方案1】:

    不推荐您在 SQL 查询中执行的联接类型,它可能会导致重复结果。我建议更像这样的东西:

    select 'Driver' as Type, UserId as Id, UserName as Name 
    from DriverInfo 
    where UserName like '%foo%'
    
    union 
    
    select 'Team' as Type, Id, TeamName 
    from Teams
    where TeamName like '%foo%'
    
    union 
    
    select 'Track' as Type, TrackId, TrackName 
    from Tracks
    where TrackName like '%foo%'
    

    这会给你这样的结果:

    类型 ID 名称 ---- -- ---- 司机 23 Foo 司机 73 Foo Jr. 第 27 队 Foo 队 64 队 Foobar 队 Track 98 酒吧 Foo 场

    以下是您可以使用这些结果的方法:

    while (dr.Read())
    {
    
        resultList.Add(
            new searchResult {
                Title = dr["Name"].ToString(),
                img = dr["Type"].ToString() + ".png",
                href = dr["UserId"].ToString() } );
    }
    

    按原样,您可能会得到这样的结果(笛卡尔积),其中结果的数量不是A + B + C,而是A * B * C

    UserId 用户名 Id TeamName TrackId TrackName ... ------ -------- -- -------- -------- --------- --- 23 Foo 27 团队 Foo 98 酒吧 Foo 场... 23 Foo 64 Team Foobar 98 Bar Foo Field ... 73 Foo Jr. 27 Team Foo 98 Bar Foo Field ... 73 Foo Jr. 64 Team Foobar 98 Bar Foo Field ...

    另外,请注意,由于使用了select *,您将获得比您需要的更多的列。

    更新

    您说您不确定如何将变量添加到查询中。您应该使用参数化查询而不是字符串连接来使您的代码更清晰并防止 SQL 注入攻击:

    cmd.CommandText = "... where UserName like @SearchPattern ... where TeamName like @SearchPattern ...";
    cmd.Parameters.Add("@SearchPattern", txtSearch + "%");
    

    【讨论】:

    • 完全是 phoog 的回答。它会一直搜索,没有任何匹配项
    • 您确定搜索并不慢,或者您在运行查询时没有遇到错误?你有很多行吗?如果没有正确的索引,执行like '%...%' 通常是一项非常昂贵的操作。尝试直接在数据库上运行查询(即,如果您使用的是 MSSQL,则使用 SQL Management Studio)。
    • 在管理工作室中正常工作。我们可以打开一个聊天对话来解决这个问题吗?
    • 哈,我真的不知道怎么把它变成聊天。如果查询在 Management Studio 中运行,那么您的代码中一定会出现运行时错误。如果您发布您遇到的错误,我们可以进一步帮助您。
    • 问题似乎是我不知道如何将该查询转换为 C# 中的字符串。我的意思是所有的“”和东西。你能帮我解决这个问题吗?
    【解决方案2】:

    是笛卡尔积查询:SELECT * FROM [DriverInfo], [Teams], [Tracks] WHERE UserName LIKE '" + txtSearch + "%' OR TeamName LIKE '" + txtSearch + "%' OR TrackName LIKE '" + txtSearch + "%'"

    (在网上搜索cartesian product join 以获取更多信息。)

    我想您要么想加入这些表,要么将它们合并。从你的例子来看,我希望这将是一个工会。这样做的好处是让 db 服务器做更多的工作,并且减少了网络流量。

    例子:

    command.CommandText = "SELECT UserName FROM [DriverInfo]"
        + "WHERE UserName LIKE '" + txtSearch + "%'"
        + "UNION SELECT TeamName FROM [Teams]"
        + "WHERE TeamName LIKE '" + txtSearch + "%'"
        + "UNION SELECT TrackName FROM [Tracks]"
        + "WHERE TrackName LIKE '" + txtSearch + "%'"
    

    但您确实必须使用参数而不是内联连接 txtSearch 值。否则你很容易受到 SQL 注入攻击。 (在网上搜索SQL injection attack 了解更多信息。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 2012-11-05
      • 1970-01-01
      • 2014-02-25
      • 1970-01-01
      • 2011-08-29
      相关资源
      最近更新 更多