I'm still fairly new to Entity Framework (currently developing using v4.1), so I may be going about this in completely the wrong way, so I'd welcome any guidance.
I currently have two classes: Item which just has a few simple fields, and FavouriteItem which holds a reference to an item and a user (but the user relationship isn't relevant to the discussion). The item has a nullable DateVisible field which I'm using as a flag to indicate if an item should be displayed or not.
In order to get a list of visible items, I'm using a simple query:
var items = itemRepository
.QueryAll()
.Where(i => i.DateVisible <= DateTime.Now)
Where obviously QueryAll returns an IQueryable. This is a straightforward example, as the conditions are a little more complex, but it demonstrates my issue.
Next, if I want to return a list of favourites for items which are visible, then I can do a similar query:
var favourites= favouriteRepository
.QueryAll()
.Where(f => f.Item.DateVisible <= DateTime.Now)
This works fine. However, the code is duplicated. So what I'd like to do is somehow make this code more central - as I'm about to add a FollowingItem class which again has an Item property, and so I'd have to repeat the code again - not good.
I started to create an expression for the list of items, which works well:
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()
And again, I can create these expressions for each class:
public static Expression<Func<FavouriteItem, bool>> IsVisibleExpression<FavouriteItem>()
{
return favourite => favourite.Item.DateVisible != null &&
favourite.Item.DateVisible <= DateTime.Now;
}
But this again just duplicates the code. Is there any way the same code be used between them. I know I could do a join on the itemRepository.QueryAll().WhereVisible()
, but is there not a way to do this that doesn't involve doing this everywhere?
Update: I tried creating an interface for the classes:
public interface IEntityWithItem
{
Item Item { get; set; }
}
And creating an expression for it:
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);
}
Which I've called from:
// Get the favourites
var favourites = favouriteItemRepository.QueryAll()
.WhereItemVisible()
.Where(favourite => favourite.UserId == user.Id);
But it gives the error: "Unable to cast the type 'FavouriteItem' to type 'IEntityWithItem'. LINQ to Entities only supports casting Entity Data Model primitive types."