[英]Entity Framework - expression on similar properties
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.我对 Entity Framework(目前正在使用 v4.1 进行开发)还是很陌生,所以我可能会以完全错误的方式来解决这个问题,所以我欢迎任何指导。
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).我目前有两个类:只有几个简单字段的Item和保存对项目和用户的引用的FavouriteItem (但用户关系与讨论无关)。 The item has a nullable DateVisible field which I'm using as a flag to indicate if an item should be displayed or not.该项目有一个可为空的DateVisible字段,我将其用作指示是否应显示某项目的标志。
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.显然 QueryAll 返回一个 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.所以我想要做的是以某种方式使这段代码更集中 - 因为我将添加一个FollowItem类,该类再次具有 Item 属性,所以我不得不再次重复该代码 - 不好。
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?我知道我可以在itemRepository.QueryAll().WhereVisible()
上做一个连接,但是有没有办法做到这一点而不涉及在任何地方都这样做?
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. "但它给出了错误:“无法将类型 'FavouriteItem' 转换为类型 'IEntityWithItem'。LINQ to Entities 仅支持转换实体数据模型原始类型。 ”
There is to my knowledge no easy way to achieve this, however have a look at PredicateBuilder, which does solve some of these issues: http://www.albahari.com/nutshell/predicatebuilder.aspx .据我所知,没有简单的方法可以实现这一点,但是看看 PredicateBuilder,它确实解决了其中一些问题: http : //www.albahari.com/nutshell/predicatebuilder.aspx 。
The basic idea is that you define interfaces with the common properties, which allows you to define generic expressions constrained to that interface.基本思想是您定义具有公共属性的接口,这允许您定义约束到该接口的通用表达式。
Start by definining these interfaces:首先定义这些接口:
public interface IHaveItem
{
Item Item {get;}
}
public interface IDateVisible
{
DateTime? DateVisible {get;}
}
This will allow you to write the query expressions in a generic way, obtaining at least some reuse:这将允许您以通用方式编写查询表达式,至少获得一些重用:
public static Expression<Func<T,bool>> IsVisible<T>(DateTime now)
where T:IHaveItem
{
return x => x.Item.DateVisible != null &&
x.Item.DateVisible < now;
}
You will still not be able to easily achieve reuse between expressions like x.DateVisible
and x.Item.DateVisible
however.但是,您仍然无法轻松实现x.DateVisible
和x.Item.DateVisible
等表达式之间的重用。
UPDATE: it turns out that 'unnecessary' cast operations are being added in the generated expression tree, which are then not supported by the entity framework provider when translating to SQL.更新:事实证明,在生成的表达式树中添加了“不必要的”转换操作,然后在转换为 SQL 时实体框架提供程序不支持这些操作。
You can apply a similar trick as the one in this question to remove these unnecessary cast operations 'manually'.您可以应用与此问题中的技巧类似的技巧来“手动”删除这些不必要的强制转换操作。 Becomes a bit hairy though IMHO...虽然恕我直言,但变得有点毛茸茸......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.