使用LINQ进行全文搜索

本文关键字:搜索 文搜索 LINQ 使用 | 更新日期: 2023-09-27 18:20:34

我正在尝试实现一个搜索函数,其中可以将结果填充到Gridview中。我正在使用LINQ在c#中查询我的数据库。

我想弄清楚的问题是,如果用户想在多个列/字段中搜索多个搜索词,那么我该怎么做?例如,如果我搜索一个包含这3个字段的表,我会得到一些数据,比如:>firstName|lastname|玩家#>gt;1.迈克尔|乔丹| 12>gt;2.迈克尔|乔丹| 24>gt;3.迈克尔|Jordan |45>gt;4.德安德烈|Jordan |6>gt;5.杰罗姆|Jordan |44>gt;6.乔丹|火花|88

现在,如果我搜索乔丹,我会得到一切:

如果我搜索迈克尔·乔丹,我应该会找到第1、2、3排。

如果我搜索Jordan Sparks 88,我应该排回第6位。

所以我的问题是我不知道搜索词在表中的位置,所以我必须搜索所有列/字段。在我当前的代码中,我遍历了每个列/字段名称,然后使用Contains(),然后使用||("或"),但它只适用于1个搜索项。

有没有一种优雅而简单的方法可以在整个linq表中进行搜索和筛选,从而最小化列表?从那里我将把结果添加到数据源中,然后绑定它

@Sphinxxx我使用的是典型的网格视图。它看起来像这样:

    <asp:GridView ID="GridView" runat="server" AllowSorting="True" PagerStyle-Mode="NumericPages"
                                AutoGenerateColumns="false" Width="100%" CssClass="gridView" OnPageIndexChanging="GridView_PageIndexChanging"
                                AllowPaging="True"  DataKeyNames="idPlayersList" OnRowCommand="GridView_RowCommand"
                                OnRowEditing="GridView_RowEditing" OnRowCancelingEdit="GridView_CancelEditRow"
                                OnRowUpdating="GridView_UpdateRow" OnRowDataBound="GridView_RowDataBound">
                                <RowStyle CssClass="rowStyle"></RowStyle>
                                    <asp:BoundField DataField="FirstName" HeaderText="First Name" SortExpression="FirstName" />
                                    <asp:BoundField DataField="LastName" HeaderText="Last Name" SortExpression="LastName" />
<asp:BoundField DataField="PlayersNumber" HeaderText="Players Number" SortExpression="PlayersNumber" />
<asp:TemplateField HeaderText="Team" SortExpression="Team">
                                    <EditItemTemplate>
                                        <asp:DropDownList ID="ddlTeam" runat="server" CssClass="dropdown" AutoPostBack="True"
                                            AppendDataBoundItems="true" DataTextField="TeamName" DataValueField="idTeam">
                                        </asp:DropDownList>
                                    </EditItemTemplate>
                                    <ItemTemplate>
                                        <asp:Label ID="lblTeam" runat="server" Text='<%# Bind("TeamName") %>'></asp:Label>
                                    </ItemTemplate>
                                </asp:TemplateField>

我当前的搜索功能如下:

/**
* This method is for button search functionality 
* 
*/
protected void btnSearch_Click(object sender, EventArgs e)
{
    // Call to Entity Model Framework
    DBModel.DBEntities context = new DBModel.DBEntities();
    
    string[] searchTerms = txtSearch.Text.Trim().Split('&');
//Prepare to build a "players" query:
IQueryable<DBModel.playersList> playersListQuery = context.playersLists;
foreach (var term in searchTerms)
{
    //Refine our query, one search term at a time:
    playersListQuery = playersListQuery.Where(p => p.isDeleted == false && (p.FirstName.Contains(term.Trim()) ||
                                           p.LastName.Contains(term.Trim()) ||
                                           p.PlayersNumber.Contains(term.Trim()) ||
                                           p.Team.Name.Contains(term.Trim())));
}
//Now we have the complete query. Get the results from the database:
var filteredplayersList = playersListQuery.Select(s => new
                                           {
                                               idPlayersList = s.idPlayersList,
                                               FirstName = s.FirstName,
                                               LastName = s.LastName,
                                               PlayersNumber  = s.PlayersNumber,
                                               TeamName  = s.Team.Name
                                            }).ToList();

GridView.DataSource = filteredplayersList; //Connecting query to the datasource Gridview
GridView.DataBind();  //Binding Gridview
}

使用LINQ进行全文搜索

幸运的是,在Linq2SQL中创建多个AND(每个搜索项一个)很容易-只需不断向查询中添加.Where(..即可:

string[] searchTerms = "Jordan Sparks 88".Split(' ');
using (var dc = new MyDataContext())
{
    //Using DataContext.Log is handy 
    //if we want to look at Linq2SQL's generated SQL:
    dc.Log = new System.IO.StringWriter();
    //Prepare to build a "players" query:
    IQueryable<Player> playersQuery = dc.Players;
    //Refine our query, one search term at a time:
    foreach (var term in searchTerms)
    {
        //Create (and use) a local variable of the search term
        //to avoid the "outer variable trap":
        //http://stackoverflow.com/questions/3416758
        //http://stackoverflow.com/questions/295593
        var currentTerm = term.Trim();
        playersQuery = playersQuery.Where(p => (p.isDeleted == false)
                                                &&
                                               (p.FirstName.Contains(currentTerm) ||
                                                p.LastName.Contains(currentTerm) ||
                                                p.PlayersNumber.Contains(currentTerm) ||
                                                p.Team.Name.Contains(currentTerm))
                                            );
    }
    //Now we have the complete query. Get the results from the database:
    var filteredPlayers = playersQuery.Select(p => new
                                                   {
                                                       p.idPlayer,
                                                       p.FirstName,
                                                       p.LastName,
                                                       p.PlayersNumber,
                                                       TeamName = p.Team.Name
                                                   })
                                      .ToArray();
    //See if the generated SQL looked like it was supposed to:
    var sql = dc.Log.ToString();
}

如果您只需要对所有属性使用Contains条件,那么您可以将所需的所有属性封装到一个属性中,然后您可以使用更少的字段应用LINQ表达式,它看起来会更干净。

public class Player
{
    public string SearchField { get => string.Format("{0}{1}{2}{3}",FirstName,LastName,PlayersNumber,Team); }
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string PlayersNumber {get; set;}
    public string Team {get; set;}
}

更好的是,我建议您在创建对象实例时在构造函数中设置SearchField,这将提高性能,避免为每次调用创建子字符串。

public string SearchField { get; private set; }
public Player(string firstName, string lastName, playersNumber, string team)
{
    FirstName = firstName;
    LastName = lastName;
    PlayersNumber = playersNumber;
    Team = team;
    SearchField = string.Format("{0}{1}{2}{3}",firstName,lastName,playersNumber,team);
}

然后您只需通过SearchField属性进行筛选

 foreach (var term in searchTerms)
 {
     var currentTerm = term.Trim();
     playersQuery = playersQuery.Where(p => p.isDeleted == false && 
                                            p.SearchField.Contains(currentTerm));
 }

现在,您有了一个具有较少字段的LINQ表达式,这将获得完全相同的结果集。

我刚刚看到的另一件事是,您提到您正在使用LINQ to SQL查询,您可以通过在SQL表中创建一个计算列来应用相同的方法,该列连接多个列的值,自SQL Server 2012以来,您可以这样做。

希望有人觉得这个解决方案有帮助。

问候!