4

我目前正在使用 Entity Framework 4 处理一个项目,该项目使用 Table Per Hierarchy 来表示使用单个表的一组类。其工作方式是该表表示状态,并且不同的状态与不同的其他类相关联。

所以你可能会想象它看起来像这样,忽略所有州共享的公共字段:

InactiveState 
  has a -> StateStore

ActiveState 
  has a -> ActivityLocation

CompletedState
  has a -> CompletionDate

每个状态都有属于它的所有 InventoryItems 的集合。

现在我的库存中的每个项目都有许多状态,历史中的最后一个是当前状态。为了保存在列表中,我有一个快捷方式字段指向我的库存当前状态:

public class InventoryItem : Entity
{

    // whole bunch of other properties

    public virtual ICollection<InventoryState> StateHistory { get; set; }

    public virtual InventoryState LastState { get; set; }

}

我遇到的第一个问题是,例如,当我想查找所有处于该Active状态的 InventoryItems 时。

事实证明Linq-To-Entities 不支持 GetType()所以我不能使用像InventoryRepository.Get().Where( x => x.LastState.GetType() == someType ). 我可以使用is运算符,但这需要一个固定的类型,所以不能有这样的方法:

 public ICollection<InventoryItem> GetInventoryItemsByState( Type state )
 {
     return inventoryRepository.Get().Where( x => x.LastState is state );
 }

在进行 Linq 查询之前,我必须根据类型运行某种 if 语句,这感觉不对。InventoryItem 列表可能会变大,因此我需要在 EF 级别执行此操作,例如,我无法将整个列表拉入内存并使用 GetType()。

在这种情况下,我有两个问题,它们之间的联系足够紧密,我认为它们可以结合起来,因为它们可能反映了我缺乏理解:

  • 是否可以使用 Linq To Entities 找到共享子表类型的项目列表?
  • 鉴于我没有使用延迟加载,是否可以Include使用 TPH 为子表类型关联项目,例如,如果我有一个 InactiveState 作为我的 InventoryItem 的子项,我可以为该 InactiveState 预加载 StateStore?
4

1 回答 1

3

是否可以使用 Linq To Entities 找到共享子表类型的项目列表?

我认为除了使用 if/switch 检查类型并使用is Tor构建过滤器表达式之外,不可能有其他方式OfType<T>。您可以将此逻辑封装到扩展方法中,例如拥有一个可维护的位置和一个可重用的方法:

public static class Extensions
{
    public static IQueryable<InventoryItem> WhereIsLastState(
        this IQueryable<InventoryItem> query, Type state)
    {
        if (state == typeof(InactiveState))
            return query.Where(i => i.LastState is InactiveState);
        if (state == typeof(ActiveState))
            return query.Where(i => i.LastState is ActiveState);
        if (state == typeof(CompletedState))
            return query.Where(i => i.LastState is CompletedState);

        throw new InvalidOperationException("Unsupported type...");
    }
}

像这样使用:

public ICollection<InventoryItem> GetInventoryItemsByState(Type state)
{
   return inventoryRepository.Get().WhereIsLastState(state).ToList();
}

我不知道是否可以使用 .NET API 并基于传递到方法中i => i.LastState is XXX手动构建表达式。(老实说,我也会感兴趣,但我几乎不知道如何自己回答这个问题。)ExpressionType

鉴于我没有使用延迟加载,是否可以使用 TPH 包含子表类型的相关项,例如,如果我有一个 InactiveState 作为我的 InventoryItem 的子项,我可以为该 InactiveState 预加载 StateStore?

我不确定我是否理解正确但通常急切的加载Include不支持对特定包含的子项的任何过滤或附加操作。

规避此限制并仍然在单个数据库往返中获得结果的一种方法是使用如下所示的投影:

var result = context.InventoryItems
    .Select(i => new
    {
        InventoryItem = i,
        LastState = i.LastState,
        StateStore = (i.LastState is InactiveState)
            ? (i.LastState as InactiveState).StateStore
            : null
    })
    .AsEnumerable()
    .Select(x => x.InventoryItem)
    .ToList();

如果查询是跟踪查询(在上面的示例中)并且关系不是多对多的(它们不在您的示例中),那么当实体加载到上下文中时,上下文将修复关系,即isInventoryItem.LastStateInventoryItem.LastState.StateStore(if LastStateis of type InactiveState) 将被设置为加载的实体(就好像它们已经被预先加载加载一样)。

于 2013-04-18T17:47:35.163 回答