使用Linq To SQL进行简单搜索

3
这个查询有什么问题,我该如何修复它?
public JsonResult Find(string q)
{
    var k = new List<string>(q.Split(' '));

    return Json(_dataContext.Jobs
        .OrderBy(p => new List<string>(p.Keywords.Split(' ')).Where(n => k.Contains(n)).Count())
        .Select(p => new { p.Title, p.IsFullTime, p.Location, p.Category, p.Url, p.Id }),
        JsonRequestBehavior.AllowGet);
 }

它抛出如下错误:

方法 'System.String[] Split(Char[])' 无法被转换为 SQL。

该代码旨在按照每行中 Keywordsq 共享单词的数量对结果进行排序,因此您共享的单词越多,排名越高。

谢谢。

另外:如果可以使用Lucene.NET来改进这段代码,我很乐意看到一个简短的例子 :)


与您的问题无关:您不需要在每个地方使用 new List<T>。您可以直接使用 Split 的结果。 - Timwi
3个回答

2
.OrderBy(p => new List(p.Keywords.Split(' ')))
嗯,信息很清楚。String.Split()无法转换为SQL。
在单个Linq-to-Sql语句中没有真正好的方法来做到这一点。我建议使用L2S将数据提取出来,放入List<>中,然后在那里进行排序。
    var jobs  = from p in _dataContext.Jobs
    select new 
      {
        p.Title,
        p.IsFullTIme,
        p.Location,
        p.Category,
        p.Url,
        p.Id,
        p.Keywords
      }

      return Json(job.ToList()
            .OrderBy(p=>p.Keywords.Split(' ').Where(n=>k.Contains(n)).Count()),
             JsonRequestBehavior.AllowGet);

然而,你真正的问题在于你有一个非常糟糕的设计。适当的第三范式应该有一个JobKeywords表(int JobId,varchar Keyword),每个工作关键字都有一行记录。然后你可以用一个SQL语句解决这个问题:

 return Json(from p in _dataContext.Jobs     
             order by p.Keywords.Intersect(k).Count()
             select new { p.Title, p.IsFullTime, p.Location, 
                          p.Category, p.Url, p.Id },     
        JsonRequestBehavior.AllowGet);            

1

你可以从SQL-land检索所有数据,并在C#-land中进行字符串拆分:

public JsonResult Find(string q)
{
    var k = q.Split(' ');

    return Json(_dataContext.Jobs
        // Select all the columns we need, including Keywords
        // (still in SQL-land)
        .Select(p => new { p.Title, p.IsFullTime, p.Location, p.Category,
                           p.Url, p.Id, p.Keywords })
        // Move into C#-land
        .AsEnumerable()
        // Do the sorting here in C#-land
        .OrderBy(p => p.Keywords.Split(' ').Count(n => k.Contains(n)))
        // Finally, remove the Keywords column we no longer need
        .Select(p => new { p.Title, p.IsFullTime, p.Location, p.Category,
                           p.Url, p.Id }),
        JsonRequestBehavior.AllowGet);
 }

然而,这样做会很慢,因为每次都要检索整个 Jobs 表,即使你在末尾添加了 .Take(n) 来获取前 n 个条目。


原本的代码也会返回整个Job表。 - James Curran
1
"AsEnumerable" 只是返回相同的列表。在 "IQueryable" 上没有定义这样的操作。您需要使用 "ToList"(或类似方法)来进行实际检索。然而,"AsEnumerable" 允许由于参数是委托,在后续调用中从 SQL 转换到 .NET。 - leppie
@Ieppie:你说得没错,AsEnumerable()实际上并不执行检索,但我认为这里并不重要。毫无疑问,不需要列表。 - Timwi

0

你不能使用 p.Keywords.Split(' ')。LINQ-to-SQL 不支持它。而且你为什么要按列表排序呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接