2011-12-23 27 views
0

現在、オートコンプリート検索フォームを使用するWebアプリケーションを開発中です。結果はSQLデータベースから更新されています。一つのことを除いて、すべての "機能性"が働いています。クライアントは配列をクライアントに返すC#Webserviceを呼び出しています。事はです。クライアントのリストには、同じ結果が複数回表示されます。したがって、データベースから1つしか一致しない場合、クライアントは縦リストに20〜25回一致することを示します。私はこれを解決する方法を知らない、助けてください。オートコンプリート検索リストの問題

C#のWebサービス:

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

SQLクエリで実行している結合のタイプは推奨されておらず、重複した結果が考慮されている可能性があります(詳細については、SQL injection attackを検索してください)。

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 + "%"); 
+0

偽の答えとまったく同じです。それは一致なしで永遠に検索を続けます – parek

+0

検索が遅くないか、またはクエリを実行中にエラーが発生していないと確信していますか?あなたはたくさんの行を持っていますか? 'like '%...%''を実行するのは、通常、適切な索引付けを行わないと非常に高価な操作です。データベースで直接クエリを実行してみてください(MSSQLを使用している場合はSQL Management Studioを使用してください)。 – Jacob

+0

管理スタジオで正しく機能しました。これを修正するためにチャットの会話を開いてください。 – parek

1

それはデカルト積のQUEですRY:SELECT * FROM [DriverInfo], [Teams], [Tracks] WHERE UserName LIKE '" + txtSearch + "%' OR TeamName LIKE '" + txtSearch + "%' OR TrackName LIKE '" + txtSearch + "%'"

(。詳細についてはcartesian product joinをウェブで検索する)

私はあなたがテーブルを結合またはそれらの組合を作りたいのいずれかとします。あなたの例から、私はそれが組合であると期待しています。これには、dbサーバに多くの作業をさせる利点があり、ネットワークトラフィックを減らすことができます。

例:あなたは本当にtxtSearch値をインラインで連結するのではなく、パラメータを使用する必要があります

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 + "%'" 

しかし。それ以外の場合は、SQLインジェクション攻撃に対して深刻な脆弱性があります。

+0

私はそれを訂正してください。 – parek

+0

それは動作しませんでした。今度は検索が永久にロードされます。 – parek