3

私はまだEntityFramework(現在v4.1を使用して開発中)にかなり慣れていないので、これを完全に間違った方法で行っている可能性があるので、ガイダンスを歓迎します。

現在、2つのクラスがあります。いくつかの単純なフィールドを持つItemと、アイテムとユーザーへの参照を保持するFavouriteItemです(ただし、ユーザーの関係はディスカッションとは関係ありません)。アイテムにはnull許容のDateVisibleフィールドがあり、アイテムを表示するかどうかを示すフラグとして使用しています。

表示されているアイテムのリストを取得するために、簡単なクエリを使用しています。

var items = itemRepository
               .QueryAll()
               .Where(i => i.DateVisible <= DateTime.Now)

明らかにQueryAllがIQueryableを返す場合。条件がもう少し複雑なので、これは簡単な例ですが、私の問題を示しています。

次に、表示されているアイテムのお気に入りのリストを返したい場合は、同様のクエリを実行できます。

var favourites= favouriteRepository
                   .QueryAll()
                   .Where(f => f.Item.DateVisible <= DateTime.Now)

これは正常に機能します。ただし、コードは重複しています。だから私がやりたいのは、どういうわけかこのコードをより中心的なものにすることです-再びItemプロパティを持つFollowingItemクラスを追加しようとしているので、コードをもう一度繰り返す必要があります-良くありません。

アイテムのリストの式を作成し始めました。これはうまく機能します。

public static Expression<Func<Item, bool>> IsVisibleExpression<Item>()
{
     return item => item.DateVisible != null && 
                    item.DateVisible <= DateTime.Now;
}

public static IQueryable<Item> WhereVisible<Item>(this IQueryable<Item> queryable)
{
     return queryable.Where(Item.IsVisibleExpression());
}

var items = itemRepository
               .QueryAll()
               .WhereVisible()

また、クラスごとに次の式を作成できます。

public static Expression<Func<FavouriteItem, bool>> IsVisibleExpression<FavouriteItem>()
{
     return favourite => favourite.Item.DateVisible != null && 
                         favourite.Item.DateVisible <= DateTime.Now;
}

しかし、これもコードを複製するだけです。それらの間で同じコードを使用する方法はありますか?私はに参加できることを知っていますが、itemRepository.QueryAll().WhereVisible()これをどこでも行うことを伴わない方法はありませんか?

更新:クラスのインターフェースを作成してみました:

public interface IEntityWithItem
{
    Item Item { get; set; }
}

そして、そのための式を作成します。

    public static IQueryable<TEntity> WhereItemVisible<TEntity>(this IQueryable<TEntity> queryable) where TEntity : IEntityWithItem
    {
        return queryable.Where(ui => ui.Item.DateVisibleFrom != null &&
                                     ui.Item.DateVisibleFrom.Value <= DateTime.Now);
    }

私が呼んだもの:

// Get the favourites
var favourites = favouriteItemRepository.QueryAll()
                      .WhereItemVisible()
                      .Where(favourite => favourite.UserId == user.Id);

ただし、 「タイプ'FavouriteItem'をタイプ'IEntityWithItem'にキャストできません。LINQtoEntitiesは、エンティティデータモデルプリミティブタイプのキャストのみをサポートしています。 」というエラーが発生します。

4

1 に答える 1

0

私の知る限り、これを達成する簡単な方法はありませんが、これらの問題のいくつかを解決するPredicateBuilderを見てください:http://www.albahari.com/nutshell/predicatebuilder.aspx

基本的な考え方は、共通のプロパティを使用してインターフェイスを定義することです。これにより、そのインターフェイスに制約されたジェネリック式を定義できます。

これらのインターフェイスを定義することから始めます。

public interface IHaveItem
{
   Item Item {get;}
}

public interface IDateVisible
{
   DateTime? DateVisible {get;}
}

これにより、クエリ式を一般的な方法で記述し、少なくともある程度の再利用を得ることができます。

public static Expression<Func<T,bool>> IsVisible<T>(DateTime now) 
    where T:IHaveItem
{
   return x => x.Item.DateVisible != null &&
          x.Item.DateVisible < now;
}

x.DateVisibleただし、とのような式の間で簡単に再利用することはできませんx.Item.DateVisible

更新:生成された式ツリーに「不要な」キャスト操作が追加されていることが判明しました。これは、SQLに変換するときにエンティティフレームワークプロバイダーによってサポートされません。

この質問と同様のトリックを適用して、これらの不要なキャスト操作を「手動で」削除できます。私見ですが少し毛むくじゃらになります...

于 2012-11-14T10:01:01.820 に答える