2013 年 9 月 18 日更新
看起来没有一个简单的方法可以做到这一点。我坚持一个涉及对实体框架进行一些扩展的解决方案。
如果您想在 Entity Framework 中看到这些功能,请在用户语音网站上为它们投票,也许在这里和这里
关于 SO 有几个类似的问题,但我找不到足够新的和相似的问题来获得我正在寻找的答案。
如果这看起来像是信息过载,请跳至In Summary。
背景
我正在编写一个 WebApi REST 服务来通过 OData 端点公开一些预先存在的数据。我正在使用EntitySetContoller<TEntity, TKey>
为我完成所有繁重的工作。除了由基类路由和转换的标准 OData 参数外,我还添加了一些自定义参数,以便为我的控制器提供特定功能。
[BigText] NVarChar[4000]
我的数据库服务器是 MS SQL Server,在表的列上有一个全文索引[SomeEntity]
。
我有一个限制,我必须使用 Code First 模型。
// Model POCO
public class SomeEntity
{
public int Id { get; set; }
public string BigText { get; set; }
}
// Simple Controller
public class SomeEntityController : EntitySetController<SomeEntity, int>
{
private readonly SomeDbContext context = new SomeDbContext();
public override IQueryable<SomeEntity> Get()
{
var parameters = Request.GetQueryNameValuePairs()
.ToDictionary(p => p.Key, p => p.Value);
if (parameters.ContainsKey("BigTextContains")
(
var searchTerms = parameters["BigTextContains"];
// return something special ...
)
return this.context.SomeEntities;
}
// ... The rest is omitted for brevity.
}
问题
如何实现// return something special ...
我的例子的一部分?
显然,尼夫
return this.context.SomeEntities.Where(e =>
e.BigText.Contains(searchTerm));
是完全错误的,它组成了一个WHERE
像这样的子句
[BigText] LIKE '%' + @searchTerm + '%'
这不使用全文搜索,因此不支持复杂的搜索词,否则,性能很差。
这种方法,
return this.context.SomeEntities.SqlQuery(
"SELECT E.* FROM [dbo].[SomeEntity] E " +
"JOIN CONTAINSTABLE([SomeEntity], [BigText], @searchTerm) FTS " +
" ON FTS.[Key] = E.[Id]",
new object[] { new SqlParameter("@searchTerm", searchTerm) })
.AsQueryable();
看起来很有希望,它实际上使用了全文搜索,并且非常实用。但是,您会注意到,DbSqlQuery
从SqlQuery
函数返回的类型没有实现IQueryable
。在这里,它被强制为带有AsQueryable()
扩展名的正确返回类型,但这打破了“组合链”。将在服务器上执行的唯一语句是上面代码中指定的语句。在 OData URL 上指定的任何附加子句都将在 API 托管 Web 服务器上提供服务,而不会受益于数据库引擎的索引和基于专用集的功能。
总之
使用 Entity Framework 5 Code First 模型访问 MS SQL Server 的全文搜索CONTAINSTABLE
功能并获得“可组合”结果的最便捷方法是什么?
我需要自己写IQueryProvider
吗?我可以以某种方式扩展 EF 吗?
我不想使用 Lucene.Net,我不想使用数据库生成模型。也许我可以添加额外的包或等待 EF6,这有帮助吗?