1

JSON を jQuery datatableに返すアクションがあります。返されたデータは、渡されたパラメータに応じてフィルタリングできます。コードは次のとおりです。

public ActionResult IndexAjaxHandler(jQueryDataTableParamModel parameters) {
    var data = _mailingListRep.GetAllWithinAccount();
    IEnumerable<MailingList> filtered;

    // Filtering - THIS DOES NOT WORK!
    if (!string.IsNullOrEmpty(parameters.sSearch)) {
        filtered = data.Where(c => 
            c.MailingListName.Contains(parameters.sSearch) ||
            ((c.IsDoubleOptIn) ? "Yes" : "No").Contains(parameters.sSearch, StringComparison.OrdinalIgnoreCase) ||
            c.Created.ToString("dd MMM yyyy").Contains(parameters.sSearch) ||
            c.ActiveMembers.Count().ToString().Contains(parameters.sSearch) ||
        c.AvailableSegments.Count().ToString().Contains(parameters.sSearch)
        );
    }
    else {
        filtered = data;
    }

    // create json object
    // return;
}

問題は、これにより次のエラーが発生することです。

メソッド 'Boolean Contains(System.String, System.String, System.StringComparison)' には、サポートされている SQL への変換がありません。

しかし

同じコントローラには、JSON をデータテーブルに返す別のアクションもあり、まったく同じフィルタリング方法を使用し、正常に動作します!

public ActionResult ViewDeletedAjaxHandler(int id, jQueryDataTableParamModel parameters) {
    var list = _mailingListRep.GetByIDWithinAccount(id);
    var data = list.DeletedMembers;
    IEnumerable<MailingListMember> filtered;

    // Filtering - THIS WORKS, NO ERRORS!
    if (!string.IsNullOrEmpty(parameters.sSearch)) {
        filtered = data.Where(c => 
            c.EmailAddress.Contains(parameters.sSearch, StringComparison.OrdinalIgnoreCase) ||
            c.UnsubscribedDate.ToString("dd MMM yyyy").Contains(parameters.sSearch, StringComparison.OrdinalIgnoreCase)
        );
    }
    else {
        filtered = data;
    }

    // create json object
    // return;
}

これがなぜなのか誰か知っていますか?

参考までContains(string, comparison)に、拡張メソッドは次のとおりです。

public static bool Contains(this string source, string toCheck, StringComparison comp) {
    return source.IndexOf(toCheck, comp) >= 0;
}

エラーの意味は理解できます。コードが 1 つのアクションで機能するという事実ですが、それ以外のアクションでは完全に混乱することはありません。

事前に助けてくれてありがとう。

4

2 に答える 2

2

機能しない最初のフィルターは に適用され、IQueryable<T>機能する 2 番目のフィルターは に適用されますIEnumerable<T>。に適用する場合IQueryable<T>、フィルタは SQL に変換可能である必要がありますが、 で使用する場合IEnumerable<T>、フィルタはメモリ内で評価されます。

最初のものを機能させるには、フィルターを適用する前に呼び出しToList()て結果を強制的にメモリに格納するか、クラスから利用可能なヘルパー メソッドを使用する必要があります。EntityFunctions

于 2012-06-29T10:57:38.660 に答える
1

これを行う 1 つの方法は、これら 2 つのシナリオでデータ参照の実行時の型が異なる場合です。

たとえば、どちらもコンパイル時の型IEnumerable<T>を持ち、一方は LINQ を LINQ2SQL にするランタイム型を持ち、もう一方は LINQ2Object にする場合です。後者の作品を含むが、前者の作品を含まない

IEnumerable<Entity> data = db.GetMyLazilyEvaluatedListOfEntities();
//this will fail
data.Where(e => e.Foo.Contains("bar"));
data = new List<Entity>();
//this will work
data.Where(e => e.Foo.Contains("bar"));

whereは、評価時に SQL に変換されることdb.GetMyLazilyEvaluatedListOfEntitiesを実装するオブジェクトを返しますIQueryable<Entity>

data.ToList()where の前に呼び出すと、実行時例外を回避できます。ただし、これはデータベースからテーブル全体をフェッチし、メモリ内でフィルタリングを行います。テーブルの行数が少ない場合はあまり問題になりませんが、データを裏付けるデータベース テーブルに多数のレコードが予想される場合は、SQL に変換できるものに書き直す必要があります。

于 2012-06-29T10:55:43.517 に答える