在实体框架中查询DbContext.Set(TypeVariable) [英] Querying against DbContext.Set(TypeVariable) in Entity Framework

查看:827
本文介绍了在实体框架中查询DbContext.Set(TypeVariable)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



重新分解的工作原理是返回正确的DbSet。



但是,类型 DbContext.Set(TypeVariable).Local IList (包含类型未知)其中 - 作为 DbContext.Set< MyEntityType>()的类型。本地 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 =设置为IQueryable< IActionTarget> ;;
entity = querables.FirstOrDefault(e => e.Id == key.Id&& e.EffectiveDate == key.EffectiveDate);

所以,两个问题:



为什么不是 DbContext.Set(TypeVariable)返回一个强类型的集合?



有更好的方法吗依赖性反转?



根据要求进一步细节



这些都是关于依赖关系的。该模型包含通过EF Code First以典型方式(但通过 Repository )持久化的POCO类。一个 ActionEvaluator 采取一些传入数据,并通过Repository方法确定需要执行哪些操作 - 因此对DbSets的查询。



在原始代码,只有一种类型的传入数据(特定格式的CSV),ActionEvaluator对此数据的依赖性很强,并且知道哪些POCO类适用于哪些CSV记录。



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



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



问题是找到DbSet的两种方法之间的区别 - DbContext.Set&AnAntity>() DbContext.Set(TypeVariable)



我想我在问EF的增强功能使它们在返回值中的功能相当,但由于第二个版本的类型在运行时确定可能不可能。



这是完整的方法代码请求:

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

//首先查看本地缓存
var entity = set.Local.OfType< IActionTarget>()
.FirstOrDefault(l => l .Id == key.Id&& l.EffectiveDate == key.EffectiveDate);

if(entity == null)
{
//如果在本地找不到数据库
var querables =设置为IQueryable< IActionTarget> ;;
if(querables!= null)
{
entity = querables.FirstOrDefault(e => e.Id == key.Id&& e.EffectiveDate == key.EffectiveDate );
}
}
返回实体;
}

理想情况下,我要替换

  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);


解决方案

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

  private IActionTarget DbContextGetEntity(Type targetType,IActionTarget key)
{
动态实例= Activator.CreateInstance(targetType);
return DbContextGetEntity(instance,key);
}

private IActionTarget DbContextGetEntity< T>(T instance,IActionTarget key)
其中T:class,IActionTarget
{
var set = Context。设置< T>(TARGETTYPE);
if(set == null)
{
throw new Exception();
}

//首先查找本地缓存
var entity = set.Local
.FirstOrDefault(l => l.Id == key.Id & amp; l.EffectiveDate == key.EffectiveDate);

if(entity == null)
{
//如果在本地找不到数据库
entity = set
.FirstOrDefault(e = > e.Id == key.Id&& e.EffectiveDate == key.EffectiveDate);
}
返回实体;
}


I'm re-factoring an application to invert some dependencies. Part of the original code uses DbContext.Set<MyEntityType>() to obtain the set to query against.

With the inversion, the MyEntityType is no longer explicitly known to the code using DbContext.Set<MyEntityType>(), so now I'm using DbContext.Set(TypeVariable) instead.

The re-factoring works to the extent that the correct DbSet is being returned.

However, the type DbContext.Set(TypeVariable).Local is IList (contained type unknown) where-as the type of DbContext.Set<MyEntityType>().Local was ObservableCollection<MyEntityType>. This means that it's now impossible to do Linq against the DbSet.

The best workaround I've been able to achieve is to cast to an interface that MyEntityType and other entity types implement (some code omitted for clarity)

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);

So, two questions:

Why doesn't DbContext.Set(TypeVariable) return a strongly typed set?

Is there a better way to do the dependency inversion?

Some further details as requested

It's all about dependencies. The Model contains POCO classes which are persisted via EF Code First in the typical way (but via a Repository). An ActionEvaluator takes some incoming data, and via Repository methods, determines what actions need to occur - hence the queries against the DbSets.

In the original code, there was only one type of incoming data (CSV of a particular format) and the ActionEvaluator had a tight dependency to this data and knew which POCO classes were applicable to which CSV records.

Now, we want to expand to use different CSV formats and web api messages. To do this, we need to invert the dependencies so that the DataSource tells the ActionEvaluator what POCO classes it's records apply to. This is done by way of a Type variable.

So, the ActionEvaluator can no longer use a generic type parameter, but it can pass the type variable to the Repository which uses it to find the correct DbSet.

The problem is the difference between the two ways of finding the DbSet - DbContext.Set<AnEntity>() and DbContext.Set(TypeVariable).

I guess I'm asking for an enhancement in EF to make these two functionally equivalent in their return values, but that may not be possible since the types of the second version are determined at runtime.

Here's the full method code as requested:

    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;
    }

Ideally, I want to replace

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

with

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

解决方案

I haven't compiled it so please excuse any formatting issues - can you use the dynamic type to achieve the same thing?

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;
}

这篇关于在实体框架中查询DbContext.Set(TypeVariable)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆