Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将linq作为参数传递给实体查询,并针对不同的对象执行_C#_Linq_Entity Framework_Linq To Entities - Fatal编程技术网

C# 将linq作为参数传递给实体查询,并针对不同的对象执行

C# 将linq作为参数传递给实体查询,并针对不同的对象执行,c#,linq,entity-framework,linq-to-entities,C#,Linq,Entity Framework,Linq To Entities,我希望实现一个缓存,以便检查特定的查询是否已经执行,如果已经执行,则使用内存缓存返回数据。我可以利用EntityFramework通过DBSet的本地属性公开的内存中视图,而不是实现缓存本身 因此,我想将整个查询传递给一个方法,该方法将针对数据库和/或内存缓存运行它。但是,我的Expression/Func/IQueryable弄混了,看不出如何传递查询/表达式: 所以基类应该是这样的(这显然还不起作用…) 公共抽象类ServiceBase,其中tenty:class { 实体_context;

我希望实现一个缓存,以便检查特定的查询是否已经执行,如果已经执行,则使用内存缓存返回数据。我可以利用EntityFramework通过DBSet的本地属性公开的内存中视图,而不是实现缓存本身

因此,我想将整个查询传递给一个方法,该方法将针对数据库和/或内存缓存运行它。但是,我的Expression/Func/IQueryable弄混了,看不出如何传递查询/表达式:

所以基类应该是这样的(这显然还不起作用…)

公共抽象类ServiceBase,其中tenty:class
{
实体_context;//在构造函数中实例化
受保护列表GetData(表达式查询)
{
如果(!HasQueryExecuted(查询))
{
_context.Set().Select(query.Load();
AddQueryToExecutedList(查询);
}
返回_context.Set().Local.AsQueryable().Select(query.ToList();
}
}
我将有多个类定义它们的查询,如下所示:

public class CustomersService : ServiceBase<Customer>
{
    public List<Customer> GetCustomersWithOrders()
    {
        return GetData(c => c.Where(c => c.OrderCount > 0));
    }

    public List<Customer> GetLargestCustomersByOrder(int TopCount)
    {
        return GetData(c => c.OrderBy(c=>c.OrderCount).Take(TopCount));
    }
}
public class ProductsService : ServiceBase<Product>
{
    public List<Customer> GetAllProducts()
    {
        return GetData(p => p);
    }
    public List<Customer> GetMostOrderedProducts(int minimumOrders)
    {
        return GetData(p => p.Where(p=> p.OrderCount > minimumOrders)
                   .OrderByDescending(p=>p.OrderCount));
    }

    public List<Customer> GetAllProducts()
    {
        return GetData(p => p);
    }
}
公共类CustomerService:ServiceBase
{
公共列表GetCustomerWithOrders()
{
返回GetData(c=>c.Where(c=>c.OrderCount>0));
}
公共列表GetLargestCustomerByOrder(int TopCount)
{
返回GetData(c=>c.OrderBy(c=>c.OrderCount).Take(TopCount));
}
}
公共类产品服务:ServiceBase
{
公共列表GetAllProducts()
{
返回GetData(p=>p);
}
公共列表GetMostOrderedProducts(整数最小订单)
{
返回GetData(p=>p.Where(p=>p.OrderCount>minimumOrders)
.OrderByDescending(p=>p.OrderCount));
}
公共列表GetAllProducts()
{
返回GetData(p=>p);
}
}
这些只是人为的例子,但关键是查询可以是多种多样的,不仅限于where子句,还可以使用IQueryable上的所有标准扩展方法来查询底层数据

首先,这可能吗?GetData方法能否定义一个可以接受任何查询的参数?在上面的示例中,我声明了
query
参数以接受为IQueryable扩展Select方法指定的相同类型,但当我尝试使用简单的Where子句或OrderBy子句调用它时,会出现各种编译错误,例如:

无法将类型“bool”隐式转换为“Entities.Customer”

无法将类型“System.Linq.IORDerenumerable”隐式转换为“Entities.Customer”


但是,如果我直接在上下文中运行相同的查询,那么它的编译就很好了。那么我做错了什么呢?

你的问题是这个
表达式查询

简单地说,您的表达式是一种函数类型,它接受
tenty
并返回
tenty
。由于您的类是使用
Entities.Customer
键入的,因此它需要一个函数,该函数接受
Entities.Customer
,并返回
Entities.Customer

如果您查看您的服务类,则
p=>p
可以正常工作,但
p=>p.Where()
不会,因为
Where
返回一个IEnumerable

我认为您应该采取不同的方法并利用延迟加载

public IQueryable<TEntity> GetData<TEntity>() where TEntity : class
{
    return _context.Set<TEntity>();
}

public IQueryable<Customer> GetAllProducts()
{
    return GetData();
}

public IQueryable<Customer> GetMostOrderedProducts(int minimumOrders)
{
    return GetData().Where(p => p.OrderCount > minimumOrders)
        .OrderByDescending(p=>p.OrderCount));
}

谢谢你回答@Shoe。我意识到查询参数有问题,但需要确定查询是否已经执行,以便在数据库或本地属性(内存缓存)上运行它。我理解您的意图,但让我们想想。您可以缓存查询以节省性能(希望也可以编译查询),但与执行查询相比,它并没有节省多少时间,因为结果没有缓存。多用户环境怎么样?由于编辑/更新/删除,在本地运行查询可能会得到与在数据库上运行查询不同的结果。您的上下文对象应该是短期的,所以您的本地缓存不应该太大。每当你新建一个上下文时,你的本地缓存都是空的,所以每次你都必须重建你的查询缓存。这种特殊用法略有不同,使用数据快照时,没有其他编辑(用户所做的编辑除外,这些编辑将保留在内存中,不会持久化回数据库)。这种情况下的上下文被有效地用作缓存,因此我希望有效地利用内存中的数据。感谢您对@Shoe的帮助,我现在明白了。
public IQueryable<TEntity> GetData<TEntity>() where TEntity : class
{
    return _context.Set<TEntity>();
}

public IQueryable<Customer> GetAllProducts()
{
    return GetData();
}

public IQueryable<Customer> GetMostOrderedProducts(int minimumOrders)
{
    return GetData().Where(p => p.OrderCount > minimumOrders)
        .OrderByDescending(p=>p.OrderCount));
}
protected List<TEntity> GetData<TEntity>(Func<IEnumerable<TEntity>,
                                         IEnumerable<TEntity>> query) where TEntity : class
{
    if (!HasQueryExecuted(query))
    {  
        AddQueryToExecutedList(query); 
        return query(_context.Set<TEntity>()).ToList();
    }
    return query(_context.Set<TEntity>().Local).ToList();
}