C# 套用;列表“;将IQueryables添加到目标?

C# 套用;列表“;将IQueryables添加到目标?,c#,entity-framework,iqueryable,C#,Entity Framework,Iqueryable,我的想法是创建一个iQueryable的“列表”,这些iQueryable可以执行不同类型的操作 所以基本上: var query1 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Name == "Ronald"); var query2 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Age == 43); var query3

我的想法是创建一个iQueryable的“列表”,这些iQueryable可以执行不同类型的操作

所以基本上:

var query1 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Name == "Ronald");
var query2 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Age == 43);
var query3 = Enumerable.Empty<Person>().AsQueryable().Select(e => e.EyeColor);

var listOfQueries = new List<IQueryable<Person>
{
    query1,
    query2,
    query3
};
var query1=Enumerable.Empty().AsQueryable()。其中(e=>e.Name==“Ronald”);
var query2=Enumerable.Empty().AsQueryable(),其中(e=>e.Age==43);
var query3=Enumerable.Empty().AsQueryable().Select(e=>e.EyeColor);
var listofquerys=新列表new{姓氏=e.姓氏})//仅获取前5个人的姓氏,他们的名字是“Ronald”,年龄42岁,孩子超过25岁。
var personDomainObjects=personService.Query(personQuery)//将前5个人作为域对象(在“场景”后面映射),名字为“Ronald”,年龄42岁,孩子超过25岁。
var personDaos=personservice.Query(personQuery)//将前5个人作为DAO对象/实体框架实体,名字为“Ronald”,年龄42岁,孩子超过25岁。

这样做的原因是为了创建一种更“统一”的方式来创建和重新使用预定义的查询,然后能够对DbSet执行它们,并将结果作为域对象而不是“实体框架模型/对象”返回。这是可能的,但您需要稍微重新构造您的方法


存储过滤器 这将存储相同的信息(筛选条件),但不会将每个筛选包装在自己的
IQueryable

简短的解释

注意
Func。你可以在这里查一下

但是,假设在已知变量中设置了过滤器:

Func过滤器组合=
e=>过滤器1(e)| |过滤器2(e)| |过滤器3(e);
var myFilteredData=myContext.Set()
.其中(过滤器组合)
.ToList();

这是可能的,但您需要稍微重新设计您的方法


存储过滤器 这将存储相同的信息(筛选条件),但不会将每个筛选包装在自己的
IQueryable

简短的解释

注意
Func。你可以在这里查一下

但是,假设在已知变量中设置了过滤器:

Func过滤器组合=
e=>过滤器1(e)| |过滤器2(e)| |过滤器3(e);
var myFilteredData=myContext.Set()
.其中(过滤器组合)
.ToList();

问题之一是IQueryable的集合只有在您的DbSet有效时才有效。一旦您的DbContext被处置,您仔细填写的集合就一文不值了

因此,除了使用
DbSet

虽然乍一看它们似乎是一样的,但是
IEnumerable
IQueryable
之间还是有区别的。可枚举项中有所有内容,可以在结果序列上枚举

另一方面,Queryable包含一个表达式和一个提供程序。提供者知道在哪里可以获取数据。这通常是一个数据库,但也可以是一个CSV文件或其他可以获取序列的项目。提供者的任务是解释表达式并将其转换为数据库可以理解的格式,通常是SQL

将linq语句连接成一个大的linq语句时,不会访问数据库。只更改了表达式

调用GetEnumerator()和MoveNext()后(通常通过执行ForEach、ToList()或类似操作),表达式将发送给提供者,提供者将其转换为数据库理解的查询格式并执行查询。查询的结果是一个可枚举序列,因此调用提供程序查询结果的Getenumerator()和MoveNext()

因为您的IQueryable持有此提供程序,所以在释放该提供程序后,您无法再枚举

当使用实体框架时,DbSet持有提供者。在提供程序中,是DbContext保存的数据库信息。处置DbContext后,您将无法再使用IQueryable:

IQueryable<Person> query = null;
using (var dbContext = new MyDbcontext())
{
     query = dbContext.Persons.Where(person => person.Age > 20);
}
foreach (var person in query)
{
      // expect exception: the DbContext is already Disposed
}
IQueryable查询=null;
使用(var dbContext=new MyDbcontext())
{
query=dbContext.Persons.Where(person=>person.Age>20);
}
foreach(查询中的var人员)
{
//预期异常:DbContext已被释放
}
因此,您不能将提供程序放入集合或可能的查询中。然而,你可以记住这个表达。您对表达式的唯一要求是它返回一个人。您还需要一个接受此表达式的函数和一个QueryProvider,以便人员将其转换为IQueryable

让我们为此创建一个通用函数,以便它可以用于任何类型,而不仅仅是个人:

static IQueryable<TSource> ToQueryable<TSource>(this IQueryProvider provider, 
    Expression expression)
{
     return provider.CreateQuery(expression);
}
static IQueryable to queryable(此IQueryProvider,
表达式(表达式)
{
返回provider.CreateQuery(表达式);
}
//那么,让我们再添加以下内容:

static IQueryable<Tsource> ToQueryable<TSource>(this DbContext dbContext, 
     Expression expression)
{
     return dbContext.Set<TSource>.Provider.ToQueryable<TSource>(expression);
}
static IQueryable to queryable(这个DbContext,
表达式(表达式)
{
返回dbContext.Set.Provider.ToQueryable(表达式);
}
有关扩展函数的帮助,请参阅

现在只需创建表达式集合一次。要快速查找,请将其设置为字典:

enum PersonQuery
{
    ByFirstname,
    ByAge,
    ByHasChildWithAgeOver,
    Skip,
}

public IReadOnlyDictionary<PersonQuery, Expression> CreateExpressions()
{
    Dictionary<PersonQuery, Expression> dict = new Dictionary<PersonQuery, Expression>();
    using (var dbContext = new MyDbContext())
    {
         IQueryable<Person> queryByFirstName = dbContext.Persons
             .Where(...);
         dict.Add(PersonQuery.ByfirstName, queryByFirstName.Expression);
         ... // etc for the other queries
    }
    return dict.
}
enum PersonQuery
{
直呼其名,
按年龄,
到了岁的时候,
跳过
}
公共IReadOnlyDictionary CreateExpressions()
{
Dictionary dict=新字典();
使用(var dbContext=new MyDbContext())
{
IQueryable QueryFirstName=dbContext.Persons
.其中(…);
dict.Add(PersonQuery.ByfirstName,queryByFirstName.Expression);
…//用于其他查询的etc
}
返回命令。
}
用法:

IReadOnlyCollection<Person> PerformQuery(PersonQuery queryId)
{
     using (var dbContext = new MyDbContext())
     {
          // get the Expression from the dictionary:
          var expression = this.QueryDictionary[queryId];
          // translate to IQueryable:
          var query = dbContext.ToQueryable<Person>(expression);
          // perform the query:
          return query.ToList();

          // because all items are fetched by now, the DbContext may be Disposed
     }
}
IReadOnlyCollection性能
var myFilteredData = myContext.Set<Person>().AsQueryable();

foreach(var filter in listOfFilters)
{
    myFilteredData = myFilteredData.Where(filter);
}
Func<Person, bool> filterCombined = 
              e => filter1(e) || filter2(e) || filter3(e);

var myFilteredData = myContext.Set<Person>()
                                 .Where(filterCombined)
                                 .ToList();
IQueryable<Person> query = null;
using (var dbContext = new MyDbcontext())
{
     query = dbContext.Persons.Where(person => person.Age > 20);
}
foreach (var person in query)
{
      // expect exception: the DbContext is already Disposed
}
static IQueryable<TSource> ToQueryable<TSource>(this IQueryProvider provider, 
    Expression expression)
{
     return provider.CreateQuery(expression);
}
static IQueryable<Tsource> ToQueryable<TSource>(this DbContext dbContext, 
     Expression expression)
{
     return dbContext.Set<TSource>.Provider.ToQueryable<TSource>(expression);
}
enum PersonQuery
{
    ByFirstname,
    ByAge,
    ByHasChildWithAgeOver,
    Skip,
}

public IReadOnlyDictionary<PersonQuery, Expression> CreateExpressions()
{
    Dictionary<PersonQuery, Expression> dict = new Dictionary<PersonQuery, Expression>();
    using (var dbContext = new MyDbContext())
    {
         IQueryable<Person> queryByFirstName = dbContext.Persons
             .Where(...);
         dict.Add(PersonQuery.ByfirstName, queryByFirstName.Expression);
         ... // etc for the other queries
    }
    return dict.
}
IReadOnlyCollection<Person> PerformQuery(PersonQuery queryId)
{
     using (var dbContext = new MyDbContext())
     {
          // get the Expression from the dictionary:
          var expression = this.QueryDictionary[queryId];
          // translate to IQueryable:
          var query = dbContext.ToQueryable<Person>(expression);
          // perform the query:
          return query.ToList();

          // because all items are fetched by now, the DbContext may be Disposed
     }
}