Linq LINQ to Entities非認識メソッド「System.String ToString(System.Object)」
7968 ワード
今日はLinqクエリーを書いて、jQuery EasyUIフレームワークのdataGridコントロールにデータをバインドする準備をしています.問題は時間タイプのフィールド(ModifyDate)にあります.EasyUIフレームワークでは、サービス側オブジェクトはクラスオブジェクトをJSON形式にシーケンス化してクライアントに渡し、dataGridコントロールにバインドしてレンダリングする必要がありますが、この時間型フィールドModifyDateはクライアント表示時に異常が発生したので、一応文字化けしましょう.
最初は、js関数をセットするなど、時間フィールドをクライアント処理しようとしました.
結果はさらにわけがわからず、NaNばかりで、半日も忙しく働いていた.その後、サービス側でModifyDateフィールドを文字列形式にし、JSON形式にシーケンス化することができると注意された.この考えは正しいですが、私はたくさんの回り道をしました.
まず、Sql Server 2005データベースに対して操作を行う際に、以下のコード(Linq to Entityベース)を使用しました.
最後から2行目のコードを見てください.
私は無邪気に、ToString()を1つ置くだけで万事順調だと思っていますが、間違えられたくありません.
後からEFはマルチデータベースを両立させるために書いてはいけないからだそうです.最終的に、EFはデータベースからデータを抽出する過程で、任意の(カスタムを含む)関数を勝手に追加することは許されないことが分かりました.もし私が確かにいくつかのデータを修正したいならどうしますか?答えは:ローカルクエリーLinq to Objectsを採用します!
上記のLinqクエリは、dbContext.B_SystemPageが開始したのは、Linq to Entityのデータベース向け操作に基づいていることが明らかです.Linq to Objects操作に移行するには、C#3.0に導入された匿名タイプを使用する必要があります.
まず、Linq to Entityを使用して、データベースから匿名の集合(タイプ)に所望のデータを読み込みます.
Select従文では、p文字でリードされるlambda式によって匿名の集合(newキーワードのみ)が作成され、集合要素の属性はデータベースの元のタイプ、すなわちp.ModifyDateタイプがDateTimeである.フィールドのタイプを変更していないことは明らかです.この場合、すべての所望のページングデータがメモリ内の匿名のセットlistに順調にロードされます.
次に、JSONの原材料(クラス)に変換するためのシーケンス化ターゲットクラスを定義します.
ModifyDateフィールドはstring型であり、クライアントスクリプトフレームワークEasyUIが望むタイプと同じタイプであることがわかるため、次のタスクは、メモリ内の匿名汎用集合をターゲットタイプ(SystemPageGrid)の汎用集合に投影する方法に変換され、Linq to Objectsが登場する.
最後に、匿名の汎用集合に対してSelect従文を使用して、集合内の各要素の値をターゲット型の汎用集合に投影します.その問題の鍵は、ToString()メソッドがLinq to Objectsでブロックされないことです.もちろん、カスタムメソッドも上に組み込むことができます.
最後の最後に、プログラミングでは、一歩前進したいと思っていますが、残念なことに、互換性の問題でツールがブロックされている場合は、間接的な方法を採用しても大丈夫です.もしこの方法が優雅であれば.
最初は、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;
最後の最後に、プログラミングでは、一歩前進したいと思っていますが、残念なことに、互換性の問題でツールがブロックされている場合は、間接的な方法を採用しても大丈夫です.もしこの方法が優雅であれば.