自动填充搜索列表问题

时间:2011-12-23 23:00:29

标签: c# javascript asp.net html css

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

C#Webservice:

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;
    }

2 个答案:

答案 0 :(得分:2)

不建议您在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%'

这会给你这样的结果:

Type      Id       Name
----      --       ----
Driver    23       Foo
Driver    73       Foo Jr.
Team      27       Team Foo
Team      64       Team Foobar
Track     98       Bar Foo Field

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

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  UserName      Id  TeamName       TrackId  TrackName      ...
------  --------      --  --------       -------  ---------      ---
23      Foo           27  Team Foo       98       Bar Foo Field  ...
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 + "%");

答案 1 :(得分:1)

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

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

我想你要么加入表格,要么加入它们。从你的例子来看,我希望它会成为一个联盟。这样做的好处是让数据库服务器可以完成更多的工作,并减少网络流量。

示例:

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以获取更多信息。)