在Entity Framework中查询DbContext.Set(TypeVariable)

时间:2013-03-18 16:17:08

标签: entity-framework

我正在重新分解应用程序以反转某些依赖项。部分原始代码使用DbContext.Set<MyEntityType>()来获取要查询的集合。

通过反转,使用DbContext.Set<MyEntityType>()的代码不再明确知道MyEntityType,所以现在我使用的是DbContext.Set(TypeVariable)

重新分解的工作范围是返回正确的DbSet。

但是,DbContext.Set(TypeVariable).Local类型为IList(包含类型未知),其中DbContext.Set<MyEntityType>().Local的类型为ObservableCollection<MyEntityType>。这意味着现在不可能针对DbSet做Linq。

我能够实现的最佳解决方法是转换为MyEntityType和其他实体类型实现的接口(为清晰起见,省略了一些代码)

var set = Context.Set(targetType);
var entity = set.Local.OfType<IActionTarget>()
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);
var querables = set as IQueryable<IActionTarget>;
entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);

所以,有两个问题:

为什么DbContext.Set(TypeVariable)没有返回强类型集?

有没有更好的方法来进行依赖倒置?

根据要求提供了一些进一步的详细信息

这完全取决于依赖关系。该模型包含POCO类,这些类通过EF Code First以典型方式保留(但通过存储库)。 ActionEvaluator 接收一些传入数据,并通过Repository方法确定需要执行的操作 - 因此针对DbSets的查询。

在原始代码中,只有一种类型的传入数据(特定格式的CSV),ActionEvaluator与此数据紧密相关,并且知道哪些POCO类适用于哪些CSV记录。

现在,我们要扩展为使用不同的CSV格式和网络API消息。为此,我们需要反转依赖关系,以便 DataSource 告诉ActionEvaluator它的记录适用的POCO类。这是通过Type变量完成的。

因此,ActionEvaluator不能再使用泛型类型参数,但它可以将类型变量传递给Repository,后者使用它来查找正确的DbSet。

问题在于找到DbSet的两种方式之间的区别 - DbContext.Set<AnEntity>()DbContext.Set(TypeVariable)

我想我要求EF中的增强功能使它们的返回值在功能上等效,但这可能是不可能的,因为第二个版本的类型是在运行时确定的。

以下是所要求的完整方法代码:

    private IActionTarget DbContextGetEntity(Type targetType, IActionTarget key)
    {
        var set = Context.Set(targetType);
        if (set == null)
        {
            throw new Exception("Unable to find DbSet for type '{0}'".F(targetType.Name));
        }

        // Look in the local cache first
        var entity = set.Local.OfType<IActionTarget>()
            .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

        if (entity == null)
        {
            // If not found locally, hit the database
            var querables = set as IQueryable<IActionTarget>;
            if (querables != null)
            {
                entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);
            }
        }
        return entity;
    }

理想情况下,我想要替换

var entity = set.Local.OfType<IActionTarget>()
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

var entity = set.Local.OfType(targetType)
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

1 个答案:

答案 0 :(得分:3)

我没有编译它所以请原谅任何格式问题 - 你能用动态类型来实现同样的事情吗?

private IActionTarget DbContextGetEntity(Type targetType, IActionTarget key)
{
    dynamic instance = Activator.CreateInstance(targetType);
    return DbContextGetEntity(instance, key);
}

private IActionTarget DbContextGetEntity<T>(T instance, IActionTarget key)
    where T : class, IActionTarget
{
    var set = Context.Set<T>(targetType);
    if (set == null)
    {
        throw new Exception();
    }

    // Look in the local cache first
    var entity = set.Local
        .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

    if (entity == null)
    {
        // If not found locally, hit the database
        entity = set
            .FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);
    }
    return entity;
}