1

我开始建立一个网页来优化一些搜索结果。下面的代码运行良好,如果我添加一个查询字符串(即?beds=4,它会返回正确的结果。但是,如果我指定两个查询字符串(即?beds=4&sleeps=8,它返回匹配任何一个的结果(所有有 4 张床的属性(无论睡眠)和所有有 8 张睡眠的属性(无论床),而不是两者。我需要某种 AND 语句,以便结果匹配床和睡眠?

@{
Layout = "~/_SiteLayout.cshtml";
Page.Title = "Search";

string searchText = Request.Unvalidated["searchText"];

var searchTerms = searchText.Split('"').Select((element, index) => index % 2 == 0 ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) : new string[] { element }).SelectMany(element => element).ToList();

for (int i=0; i<searchTerms.Count; i++)
{
    if (searchTerms[i].ToUpper() == "THE" || searchTerms[i].ToUpper() == "AND" || searchTerms[i].ToUpper() == "AS" || searchTerms[i].ToUpper() == "AN" || searchTerms[i].ToUpper() == "BUT" || searchTerms[i].ToUpper() == "OR" || searchTerms[i].ToUpper() == "OF" || searchTerms[i].ToUpper() == "IF" || searchTerms[i].ToUpper() == "IS" || searchTerms[i].ToUpper() == "IN" || searchTerms[i].ToUpper() == "IT" || searchTerms[i].ToUpper() == "BY" || searchTerms[i].ToUpper() == "TO" || searchTerms[i].ToUpper() == "FOR" || searchTerms[i].Length <= 1 || String.IsNullOrWhiteSpace(searchTerms[i]))
        {
        searchTerms.RemoveAt(i);
        i--;  //decrements 'i' if an element is removed because all indexes after this one will drop by one. This ensures that no indexes get skipped.
        }
}



var db = Database.Open("StayInFlorida");
string searchQueryString = "";
int termCount = searchTerms.Count;
string[] searchTermsArray = searchTerms.ToArray();

searchQueryString = "SELECT * FROM PropertyInfo WHERE numBedrooms = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
        {
        searchQueryString += "OR numBedrooms = "; //Ensures that this is not appended for the first term. Alternatively, of course, you can use "AND", depending on how you want the results returned, but you probably want "OR".
        }

searchQueryString += "@" + i + " ";
}

searchQueryString += "UNION ";
searchQueryString += "SELECT * FROM PropertyInfo WHERE numSleeps = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
        {
        searchQueryString += "OR numSleeps = ";
        }

searchQueryString += "@" + i + " ";
}

searchQueryString += "UNION ";
searchQueryString += "SELECT * FROM PropertyInfo WHERE numBathrooms = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
        {
        searchQueryString += "OR numBathrooms = ";
        }

searchQueryString += "@" + i + " ";
}

searchQueryString += "ORDER BY anyTermYouWishToOrderBy DESC";

if (searchTermsArray.Length > 0) //Prevents a server-side error if the searchTerm list was empty when converted to the searchTermsArray
    {
    var queryResults = db.Query(searchQueryString, searchTermsArray);
    }
}
4

2 回答 2

2

您有许多需要处理的替代方案:

  1. 如果指定床位数但未指定睡眠次数

  2. 如果指定了睡眠次数但未指定床位数

  3. 如果两者都指定

  4. 如果两者都没有指定

(这里有一行文字来解决此编辑器中不允许将代码直接发布在有序列表下的错误。)

var selectCommand = "SELECT * FROM PropertyInfo ";
var beds = Request["beds"].AsInt();
var sleeps = Request["sleeps"].AsInt();
IEnumerable<dynamic> selectedData = null;

if(beds > 0 && sleeps == 0) { 
    selectCommand = "SELECT * FROM PropertyInfo WHERE NumBedrooms = @0";
    selectedData = db.Query(selectCommand, beds);
}

if(sleeps > 0 && beds = 0) { 
    selectCommand = "SELECT * FROM PropertyInfo WHERE NumSleeps = @0";
    selectedData = db.Query(selectCommand, sleeps)
}

if(beds > 0 && sleeps > 0){
    selectCommand = "SELECT * FROM PropertyInfo WHERE NumBedrooms = @0 AND NumSleeps = @1";
    selectedData = db.Query(selectCommand, beds, sleeps)
}

if(beds == 0 && sleeps == 0){
    //no meaningful numbers where specified
}
于 2013-07-25T10:05:45.147 回答
2

警告:

我希望这个答案可以帮助您从逻辑上接近一种解决方案,以扩展功能以包含许多您直到运行时才知道但必须用于查询数据库的变量。我知道您不是在搜索字符串,而是在搜索数字,或者可能是其他类型的数据,这些数据可能是从前一页的表单中收集的,但是一旦您获得了目标页面所需的所有数据(使用查询字符串可能不会合适),物流应该是一样的,所以我们从那里开始。最后,如果您发现无法从表单获取未知数量的变量到目标页面,我们也可以解决这个问题,但现在我假设您已经在页面上收集了必要的数据查询数据库。

对于这个例子,我将假设用户输入了一个文本字符串,我必须将其拆分为空格,从中提取单词,并将每个单词存储在一个列表中。

首先,(对于此示例)从上一页的<form>使用中检索单个查询字符串中的值。GET这个,你已经知道怎么做了。

string searchText = Request.Unvalidated["searchText"];

请注意,我必须在未验证的情况下检索此值,因为如果用户要在搜索词中键入尖括号,则会引发服务器端错误。不过,这没关系,因为我们会小心处理不受信任的数据。

接下来,您可以简单地检查他们的整个搜索文本,以确保它不是空的或空格,如下所示:

if (!String.IsNullOrWhiteSpace(searchText))

在该分支中,您可以开始执行完成这项工作所需的所有功能。

您可以替换任何您想忽略的简单字符(我们将使用撇号和逗号)。

searchText = searchText.Replace("'", "").Replace(",", "");

现在,下一行有点复杂,我什至不确定我会正确解释它(我对 LINQ 还是很陌生),所以,只要说它有效地将字符串拆分为空格就足够了(照顾诸如双空格和将引号中的文本视为单个项目)并将它们存储在列表中(这部分可能超出您的问题范围,如果是这样,我很抱歉,但以防万一您需要使用类似的东西这个...)。

var searchTerms = searchText.Split('"').Select((element, index) => index % 2 == 0 ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) : new string[] { element }).SelectMany(element => element).ToList();

现在,如果你愿意,你可以从这个列表中省略你想忽略的词(我将在这个例子中使用一些简单的常用词,以及任何单字符项目,当然还有空、空或白色空间项目):

for (int i=0; i<searchTerms.Count; i++)
{
    if (searchTerms[i].ToUpper() == "THE" || searchTerms[i].ToUpper() == "AND" || searchTerms[i].ToUpper() == "AS" || searchTerms[i].ToUpper() == "AN" || searchTerms[i].ToUpper() == "BUT" || searchTerms[i].ToUpper() == "OR" || searchTerms[i].ToUpper() == "OF" || searchTerms[i].ToUpper() == "IF" || searchTerms[i].ToUpper() == "IS" || searchTerms[i].ToUpper() == "IN" || searchTerms[i].ToUpper() == "IT" || searchTerms[i].ToUpper() == "BY" || searchTerms[i].ToUpper() == "TO" || searchTerms[i].ToUpper() == "FOR" || searchTerms[i].Length <= 1 || String.IsNullOrWhiteSpace(searchTerms[i]))
    {
        searchTerms.RemoveAt(i);
        i--;  //decrements 'i' if an element is removed because all indexes after this one will drop by one. This ensures that no indexes get skipped.
    }
}

接下来,声明一些您需要的基本变量:

var db = Database.Open("StayInFlorida");
string searchQueryString = "";
int termCount = searchTerms.Count;
string[] searchTermsArray = searchTerms.ToArray();

现在,当您不知道要针对多少个变量来测试列时,一些逻辑将帮助您处理编译 sql 查询字符串(对于此示例,我将假设存在三个数据库列:numBedrooms、numSleeps , 和 numBathrooms)。

searchQueryString = "SELECT * FROM PropertyInfo WHERE numBedrooms = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
    {
        searchQueryString += "OR numBedrooms = "; //Ensures that this is not appended for the first term. Alternatively, of course, you can use "AND", depending on how you want the results returned, but you probably want "OR".
    }

    searchQueryString += "@" + i + " ";
}

searchQueryString += "UNION ";
searchQueryString += "SELECT * FROM PropertyInfo WHERE numSleeps = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
    {
        searchQueryString += "OR numSleeps = ";
    }

    searchQueryString += "@" + i + " ";
}

searchQueryString += "UNION ";
searchQueryString += "SELECT * FROM PropertyInfo WHERE numBathrooms = ";

for (int i=0; i<termCount; i++)
{
    if (i != 0)
    {
        searchQueryString += "OR numBathrooms = ";
    }

    searchQueryString += "@" + i + " ";
}

searchQueryString += "ORDER BY anyTermYouWishToOrderBy DESC"; //You can order by whatever term you need, and, as always, can use "ASC" instead of "DESC"

现在该部分已经结束,剩下的就是确保将适当数量的参数传递给db.Query()方法,并且由于我们已经有了列表的数组副本,我们可以使用它。

if (searchTermsArray.Length > 0) //Prevents a server-side error if the searchTerm list was empty when converted to the searchTermsArray
{
    var queryResults = db.Query(searchQueryString, searchTermsArray);

值得庆幸的是,该db.Query()方法通过接受一个值数组作为第二个参数使这变得简单,它只是填充查询中的参数,就好像您在第一个参数之后添加多个参数一样。

最后,简单展示一下结果(这部分你可能已经知道了,但为了完整起见,我还是举个例子吧)

foreach (var row in queryResults)
{
    <div>Number of Bedrooms: @row.numBedrooms</div><br/>
    <div>Number of Sleeps: @row.numSleeps</div><br/>
    <div>Number of Bathrooms: @row.numBathrooms</div><br/><hr/><br/>
}
} // <-- Don't forget to close the `if (searchTermsArray.Length > 0)` branch.
} // <-- Don't forget to close the `if (!String.IsNullOrWhiteSpace(searchText))` branch.

我知道这里 100% 的逻辑可能并不完全适合您的场景,但希望能给您足够的信息,以便您可以根据需要对其进行修改。另外,如果您有任何问题,如果可以的话,我很乐意为您提供进一步的帮助。

于 2013-07-25T16:02:17.787 回答