式をorderby句に渡すことができるようにするメソッドを書きましたが、この問題に遭遇しました。
型 'System.DateTime'を型 'System.IComparable'にキャストできません。 LINQ to EntitiesはEntity Data Modelプリミティブ型のキャストのみをサポートします。
基本的に式はこれです:
Expression<Func<K, IComparable>> orderBy
そしてこのように使われます:
SomeEntities.SomeTable
.Where
(
whereClause
)
.Select
(
selectClause
)
.OrderBy(orderBy)
このアイデアは、辞書を使って、次のような式に一致する文字列を保持できるようにするためです。
_possibleSortForForumItem.Add("CreateDate", item => item.CreateDate);
それから、ソート文字列を取り込んで辞書のキーに一致する場合は式を返し、そうでない場合はデフォルトを返すメソッドがあります。 (これは何を順序付けることができるかを制御する方法であるという考えです。)これはStringプロパティには有効ですが、上記のエラーメッセージが表示されるのでこれまでのところdatetimeまたはintegerには無効です。
私が(大まかに)問題を理解している限りでは、それはC#DateTimeをデータベースが処理できるものに変換しなければならないのでEntity FrameworkがPrimary / EDMタイプである必要があるということです。
これでも機能するように、datetimeをプリミティブ型に変換する方法はありますか?
溶液
method by orderを取得するためのメソッド:(クエリを受け取り、それを "ordered form"で返します)
private static Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> GetMethodForSort(String sortBy)
{
if (_methodForSort == null)
{
_methodForSort = new Dictionary<String, Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>>>();
_methodForSort.Add(SortForumViewItemCreatedOn, item => item.OrderBy(innerItem => innerItem.CreatedOn));
...
}
Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> orderMethod;
if(String.IsNullOrEmpty(sortBy) || !_methodForSort.ContainsKey(sortBy))
{
orderMethod = _methodForSort["ForumName"];
}
else
{
orderMethod = _methodForSort[sortBy];
}
return orderMethod;
}
ジェネリッククエリメソッドのメソッドシグネチャ
IList<K> GetListForGrid<T, K>(this ObjectQuery<T> query, ... Func<IQueryable<K>, IOrderedQueryable<K>> orderBy, ...)
そして渡されたメソッドの使用:
initialQuery = query
.Where
(
somethingEqualsSomething
)
.Select
(
selectClause
);
var orderedQuery = orderBy(initialQuery);
returnValue = orderedQuery
.Skip(numberToShow * realPage)
.Take(numberToShow)
.ToList();
Entity Frameworkではこれを困難にしています。単一の戻り値型(IComparable、objectなど)を使用してやりたいことを実行する方法があるかどうかはわかりません。あなたのデザインをname-to- Func<IQueryable<K>, IOrderedQueryable<K>>
値のFunc<IQueryable<K>, IOrderedQueryable<K>>
ことを考えるかもしれません:
_possibleSortForForumItem.Add("CreateDate",
query => query.OrderBy(item.CreateDate));
そしてそれを次のように適用します。
var orderedQuery = query.OrderBy(item => item.DefaultOrderColumn);
Func<IQueryable<K>, IOrderedQueryable<K>> assignOrderBy = null;
if (_possibleSortForForumItem.TryGetValue(orderColumnName, out assignOrderBy))
{
orderedQuery = assignOrderBy(query);
}
私はこれが古いことを知っていますが、私はOPと全く同じことを達成しようとしていたので私の辞書でFunc<IQueryable<T>, IOrderedQueryable<T>>
を使いたくありませんでした。主に、 OrderBy
とOrderByDescending
両方のデリゲートを実装する必要があるためです。
私はObjectSort
と呼ばれるIQueryableの拡張メソッドを作成することにしました。これは式の戻り型がどうなるべきかを単純にチェックし、その型を使って新しいラムダを作成してLINQ to Entitiesがおかしくならないようにします。
これが良い解決策であるかどうかはDateTime
ませんが、以下の例はDateTime
とint
ので、似たようなことを達成しようとしているのであれば、いくつかのアイデアが得られます。
public static IOrderedQueryable<T> ObjectSort<T>(this IQueryable<T> entities, Expression<Func<T, object>> expression, SortOrder order = SortOrder.Ascending)
{
var unaryExpression = expression.Body as UnaryExpression;
if (unaryExpression != null)
{
var propertyExpression = (MemberExpression)unaryExpression.Operand;
var parameters = expression.Parameters;
if (propertyExpression.Type == typeof(DateTime))
{
var newExpression = Expression.Lambda<Func<T, DateTime>>(propertyExpression, parameters);
return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
}
if (propertyExpression.Type == typeof(int))
{
var newExpression = Expression.Lambda<Func<T, int>>(propertyExpression, parameters);
return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
}
throw new NotSupportedException("Object type resolution not implemented for this type");
}
return entities.OrderBy(expression);
}