c# - Entity Framework - 类似属性的表达

标签 c# .net entity-framework entity-framework-4.1

我对 Entity Framework 还很陌生(目前使用 v4.1 开发),所以我可能会以完全错误的方式解决这个问题,所以我欢迎任何指导。

我目前有两个类: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)

这很好用。但是,代码是重复的。所以我想做的是以某种方式使这段代码更集中——因为我要添加一个 FollowingItem 类,它又具有一个 Item 属性,所以我不得不重复代码再次 - 不好。

我开始为项目列表创建一个表达式,效果很好:

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() 上做一个连接,但是有没有一种方法可以做到这一点而不需要在任何地方都这样做?

更新:我尝试为这些类创建一个接口(interface):

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’。LINQ to Entities 仅支持转换实体数据模型基元类型。

最佳答案

据我所知,没有简单的方法可以实现这一点,但是请看一下 PredicateBuilder,它确实解决了其中的一些问题:http://www.albahari.com/nutshell/predicatebuilder.aspx .

基本思想是您定义具有公共(public)属性的接口(interface),这允许您定义受限于该接口(interface)的通用表达式。

首先定义这些接口(interface):

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.DateVisiblex.Item.DateVisible 等表达式之间的重用。

更新:事实证明,在生成的表达式树中添加了“不必要的”转换操作,然后在转换为 SQL 时 Entity Framework 提供程序不支持这些操作。

您可以应用与 this question 中类似的技巧“手动”删除这些不必要的转换操作。虽然恕我直言,但变得有点毛茸茸......

关于c# - Entity Framework - 类似属性的表达,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13376326/

相关文章:

c# - .NET 列表最佳方法

entity-framework - Entity Framework 是否支持循环引用?

c# - 使用 EF 向表中添加新行时违反主键约束

c# - 如何自动调整 div 元素的大小以使内容适合

c# - 在 C# 中使用可空类型

c# - session变量赋值给数据表和创建对象引用问题?

c# - 在 Windows 事件日志中检测手动时间更改和夏令时事件

c# - 为什么我的必需属性没有在 Entity Framework Core 中级联删除?

c# - C# .NET 的区间数据类型?

entity-framework - Entity Framework 数据库第一个多个模式重复表名