16

2013年9月18日更新

これを行う簡単な方法はないようです。私は、Entity Framework の拡張を含むソリューションを待ち望んでいます。

Entity Framework でこれらの機能を確認したい場合は、ユーザーの声のサイトで投票してください


SOにはいくつかの同様の質問がありますが、探している答えを得るのに十分なほど新しくて類似した質問が見つかりません。

これが情報過多のように見える場合は、[概要] にジャンプしてください。

バックグラウンド

OData エンドポイントを介して既存のデータを公開する WebApi REST サービスを作成しています。私は を使用してEntitySetContoller<TEntity, TKey>、面倒な作業をすべて行っています。基本クラスによってルーティングおよび変換される標準の OData パラメーターに加えて、いくつかのカスタム パラメーターを追加して、コントローラーに特定の機能を許可します

私のデータベースサーバーは、テーブルの[BigText] NVarChar[4000]列に全文索引がある MS SQL Serverです。[SomeEntity]

制限が 1 つあります。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 を待つことができますか?

4

2 に答える 2

2

最近、同じ問題が発生しました: EF 5 Code First FTS Queriable

その投稿を延長させてください。

  • あなたの最初のオプションも私のものでした-SqlQueryを使用して、さらにフィルタリングを行う必要があったため、常に完全なSQLを記述する代わりに、QueryBuilderを使用しました。必要に応じて): QueryBuilder

  • 私が実装した別のアイデアを見つけた後。誰かがすでにここで言及していますが、それは Id の HashSet を返す SqlQuery を使用し、Contains を使用した EF クエリで使用できることです。メモリ内に 2 つのクエリと Id リストが必要なため、これは優れていますが、最適とは言えません。例:

        public IQueryable<Company> FullTextSearchCompaniesByName(int limit, int offset, string input, Guid accountingBureauId, string orderByColumn)
    {
        FtsQueryBuilder ftsQueryBuilder = new FtsQueryBuilder();
    
        ftsQueryBuilder.Input = FtsQueryBuilder.FormatQuery(input);
        ftsQueryBuilder.TableName = FtsQueryBuilder.GetTableName<Company>();
        ftsQueryBuilder.OrderByTable = ftsQueryBuilder.TableName;
        ftsQueryBuilder.OrderByColumn = orderByColumn;
        ftsQueryBuilder.Columns.Add("CompanyId");
    
        if (accountingBureauId != null && accountingBureauId != Guid.Empty)
            ftsQueryBuilder.AddConditionQuery<Guid>(Condition.And, "" , @"dbo.""Company"".""AccountingBureauId""", Operator.Equals, accountingBureauId, "AccountingBureauId", "");
    
        ftsQueryBuilder.AddConditionQuery<bool>(Condition.And, "", @"dbo.""Company"".""Deleted""", Operator.Equals, false, "Deleted", "");
    
        var companiesQuery = ftsQueryBuilder.BuildAndExecuteFtsQuery<Guid>(Context, limit, offset, "Name");
        TotalCountQuery = ftsQueryBuilder.Total;
        HashSet<Guid> companiesIdSet = new HashSet<Guid>(companiesQuery);
        var q = Query().Where(a => companiesIdSet.Contains(a.CompanyId));
        return q;
    }
    
  • ただし、EF 6 には、クエリ可能な FTS を実装するために使用できる Interceptors と呼ばれるものがあり、非常にシンプルで汎用的です (最後の投稿): EF 6 Interceptors for FTS。私はこれをテストしましたが、正常に動作します。

!! 備考: EF Code First は、バージョン 6 でも、カスタム ストアド プロシージャをサポートしていません。私がよく理解していれば、定義済みの CUD 操作にはいくつかしかありません: Code First Insert/Update/Delete Stored Procedure Mappingであるため、それを使用することはできません。

結論: 3 番目のオプションとして EF 6 を使用できる場合は、必要なものがすべて揃っています。EF 5 以下で行き詰まっている場合、2 番目のオプションは最初のオプションよりも優れていますが、最適ではありません。

于 2013-12-23T17:37:08.880 に答える