IQueryable扩展方法,不将DbContext作为参数传递

时间:2017-02-10 15:45:01

标签: c# entity-framework dbcontext iqueryable

这有效

var invoices = this.myContext.FilterByCustomer(this.myContext.Invoices, customerId);

它实现为:

public partial class MyContext : DbContext
{
    public IQueryable<T> FilterByCustomer<T>(IQueryable<T> queryableEntityCollection, int customerId) where T : class, ICustomerEntity
    {
        // I need to query entities from MyContext here
        // This implementation already works
    }
}

但我想要这个

var invoices = this.myContext.Invoices.FilterByCustomer(customerId);

如果我在IQueryable(DbSet)上实现扩展方法,似乎我必须将MyContext作为参数传递,我不喜欢。

public static IQueryable<T> FilterByCustomer<T>(this IQueryable<T> queryableEntityCollection, MyContext context, int customerId) where T : class, ICustomerEntity
{
    // I need to query entities from MyContext here
    // This WOULD work, I would be able to query other tables on 'context', but I don't like passing the context as parameter here
    // I don't want this implementation
}

如何实现一个IQueryable扩展,它不要求我将上下文作为参数传递?

public IQueryable<T> FilterByCustomer<T>(IQueryable<T> queryableEntityCollection, int customerId) where T : class, ICustomerEntity
{
    // I need to query entities from MyContext here, without passing MyContext as a parameter
    // I want such implementation
}

这可能吗?

3 个答案:

答案 0 :(得分:2)

你可以这样做,但它确实依赖于传递上下文但你不必传递集合。这假设您要过滤根DbSet<T>而不是已过滤的IQueryable实例。

public static IQueryable<T> FilterByCustomer<T>(this DbContext context, int customerId) where T : class, ICustomerEntity
{
    var queryableEntityCollection = context.Set<T>();
    // rest of code that filters and returns something
}

称之为:

this.myContext.FilterByCustomer<Invoice>(customerId);

如果你真的想直接在DbSet上执行此操作并从该DbSet获取DbContext,那么请参阅前面的问题/答案。 Can you get the DbContext from a DbSet?

答案 1 :(得分:1)

  

这有可能吗?

Invoice应为DbSet<TEntity>,其源自IQueryable<TEntity>所以:

public static IQueryable<T> FilterByLogin<T>(
  this IQueryable<T> query, 
  int customerId) 
  where T : ICustomerEntity
{
  var result = query.Where(cu => cu.CustomerId == customerId);

  return result;
}

接口的最小值为:

public interface ICustomerEntity
{
  public int CustomerId { get; }
}

用法:

var customers = this.myContext.Invoices
  .FilterByLogin(customerId)
  .ToList();

,其中

public class Invoice : ICustomerEntity
{
  // etc
}
  

但是,实现详细信息从上下文中查询其他实体,因此方法中需要上下文的实例。

是(sorta,扩展方法然后离开dbcontext),但它很难看:

public static IQueryable<T> FilterByLogin<T>(
  this MyContextType context
  Func<IQueryable<T>> query, 
  int customerId) 
  where T : ICustomerEntity
{
  var result = query(context)
    .Where(cu => cu.CustomerId == customerId);

  return result;
}

用法:

var customers = this.myContext
  .FilterByLogin(c => c.Invoices, customerId)
  .ToList();

它很难看,因为它在这个陈述中并不完全清楚返回的内容。

答案 2 :(得分:-1)

不要把它变成一种扩展方法。它看起来像一个存储库模式或任何你想要命名的模式。

所以你无论如何都需要将它分成自己的类。然后你也可以注入DbContext,使用它如下:

public class CustomerRepository<TCustomer>
    where TCustomer : class, ICustomerEntity
{
    public CustomerRepository(IYourContext context)
    {
        _context = context;
    }

    public IQueryable<TCustomer> FilterByCustomer(int customerId) 
    {
        var customer = _context.Customers.Where(...);

        var anotherEntity = _context.OtherEntities.Where(...);
    }
}

或者,您可以在课程中注入必要的IQueryable<T>

public class CustomerRepository
{
    public CustomerRepository(IQueryable<Customer> customers, IQueryable<OtherEntity> otherEntities)
    {           
        _customers = customers;
        _otherEntities = otherEntities;
    }

    public IQueryable<TCustomer> FilterByCustomer(int customerId) 
    {
        var customer = _customers.Where(...);

        var anotherEntity = _otherEntities.Where(...);
    }
}