在WebMatrix中搜索细化

时间:2013-07-23 12:53:36

标签: sql razor webmatrix webmatrix-2

我开始构建一个网页来优化一些搜索结果。下面的代码工作得很好,如果我添加一个查询字符串(即,?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);
    }
}

2 个答案:

答案 0 :(得分:2)

您需要处理许多其他方案:

  1. 如果指定了床位数但没有睡眠次数

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

  3. 如果同时指定了

  4. 如果两者都没有指定

  5. (这是一行文本,用于对付此编辑器中的错误,该错误不允许代码直接发布在有序列表下。)

    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
    }
    

答案 1 :(得分: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();

现在,如果您这样选择,您可以省略此列表中您要忽略的术语(我将在此示例中使用一些简单的常用词,以及任何单个字符项,当然,空,null或白色空间物品):

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%的逻辑可能不完全符合您的情况,但希望能给您足够的信息,您可以根据自己的需要对其进行修改。另外,如果您有任何问题,如果可以的话,我会很乐意提供进一步的帮助。