Linq LINQ to Entities非認識メソッド「System.String ToString(System.Object)」

7968 ワード

今日はLinqクエリーを書いて、jQuery EasyUIフレームワークのdataGridコントロールにデータをバインドする準備をしています.問題は時間タイプのフィールド(ModifyDate)にあります.EasyUIフレームワークでは、サービス側オブジェクトはクラスオブジェクトをJSON形式にシーケンス化してクライアントに渡し、dataGridコントロールにバインドしてレンダリングする必要がありますが、この時間型フィールドModifyDateはクライアント表示時に異常が発生したので、一応文字化けしましょう.
最初は、js関数をセットするなど、時間フィールドをクライアント処理しようとしました.
//     

function DateTimeFormatter(val, rec) {

    if (val) {

        var date = new Date(val.time);

        alert(val);

        var d = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();

        var t = date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();

        return d + " " + t;

    } else {

        return "";

    }

}

結果はさらにわけがわからず、NaNばかりで、半日も忙しく働いていた.その後、サービス側でModifyDateフィールドを文字列形式にし、JSON形式にシーケンス化することができると注意された.この考えは正しいですが、私はたくさんの回り道をしました.
まず、Sql Server 2005データベースに対して操作を行う際に、以下のコード(Linq to Entityベース)を使用しました.
var query = dbContext.B_SystemPage.OrderBy(p => p.PageID)

    .Where(p => p.IsDeleted == false

        && string.IsNullOrEmpty(pageName) ? true : p.PageName.Contains(pageName)

                                                || p.Remark.Contains(pageName))

    .Skip((pageNumber - 1) * pageSize).Take(pageSize)

    .Select(l => new SystemPageGrid

    {

        PageID = l.PageID,

        PageName = l.PageName,

        PageUrl = l.PageUrl,

        IsMenu = l.IsMenu,

        Remark = l.Remark,

        ModifyDate = l.ModifyDate.ToString()

    });

 
最後から2行目のコードを見てください.
l.ModifyDate.ToString()

 
私は無邪気に、ToString()を1つ置くだけで万事順調だと思っていますが、間違えられたくありません.
LINQ to Entities      “System.String ToString(System.Object)”

後からEFはマルチデータベースを両立させるために書いてはいけないからだそうです.最終的に、EFはデータベースからデータを抽出する過程で、任意の(カスタムを含む)関数を勝手に追加することは許されないことが分かりました.もし私が確かにいくつかのデータを修正したいならどうしますか?答えは:ローカルクエリーLinq to Objectsを採用します!
上記のLinqクエリは、dbContext.B_SystemPageが開始したのは、Linq to Entityのデータベース向け操作に基づいていることが明らかです.Linq to Objects操作に移行するには、C#3.0に導入された匿名タイプを使用する必要があります.
まず、Linq to Entityを使用して、データベースから匿名の集合(タイプ)に所望のデータを読み込みます.
string pageName = queryParameter["pageName"];

    //Linq to Entity

    var query = dbContext.B_SystemPage.OrderBy(p => p.PageID)

                        .Where(p => p.IsDeleted == false

                            && string.IsNullOrEmpty(pageName) ? true : p.PageName.Contains(pageName)

                                                                    || p.Remark.Contains(pageName))

                        .Skip((pageNumber - 1) * pageSize).Take(pageSize)

                        .Select(p => new

                    {

                        p.PageID,

                        p.PageName,

                        p.PageUrl,

                        p.IsMenu,

                        p.ModifyDate,

                        p.Remark

                    });

    var list = query.ToList();

 
Select従文では、p文字でリードされるlambda式によって匿名の集合(newキーワードのみ)が作成され、集合要素の属性はデータベースの元のタイプ、すなわちp.ModifyDateタイプがDateTimeである.フィールドのタイプを変更していないことは明らかです.この場合、すべての所望のページングデータがメモリ内の匿名のセットlistに順調にロードされます.
 
次に、JSONの原材料(クラス)に変換するためのシーケンス化ターゲットクラスを定義します.
public class SystemPageGrid

{

    public int PageID { set; get; }

    public string PageName { set; get; }

    public string PageUrl { set; get; }

    public bool? IsMenu { set; get; }

    public string Remark { set; get; }

    public string ModifyDate { set; get; }

}

ModifyDateフィールドはstring型であり、クライアントスクリプトフレームワークEasyUIが望むタイプと同じタイプであることがわかるため、次のタスクは、メモリ内の匿名汎用集合をターゲットタイプ(SystemPageGrid)の汎用集合に投影する方法に変換され、Linq to Objectsが登場する.
 
最後に、匿名の汎用集合に対してSelect従文を使用して、集合内の各要素の値をターゲット型の汎用集合に投影します.その問題の鍵は、ToString()メソッドがLinq to Objectsでブロックされないことです.もちろん、カスタムメソッドも上に組み込むことができます.
//Linq to Objects

pageGridList = list.Select(l => new SystemPageGrid

{

    PageID = l.PageID,

    PageName = l.PageName,

    PageUrl = l.PageUrl,

    IsMenu = l.IsMenu,

    Remark = l.Remark,

    ModifyDate = l.ModifyDate.ToString()

}).ToList();



return pageGridList;

 
最後の最後に、プログラミングでは、一歩前進したいと思っていますが、残念なことに、互換性の問題でツールがブロックされている場合は、間接的な方法を採用しても大丈夫です.もしこの方法が優雅であれば.