无需将 DbContext 作为参数传递的 IQueryable 扩展方法
IQueryable extension method without passing the DbContext as a parameter
这个有效
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
}
这可能吗?
Is that possible at all?
是的。
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
}
HOWEVER, the implementation detail queries other entities from the context, so an instance of the context is required in the method.
是的(有点,扩展方法然后脱离了 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();
这很丑陋,因为在此语句中返回的内容并不十分清楚。
不要硬塞进扩展方法中。它看起来像一个存储库模式或任何你想命名的。
因此,无论如何您都需要将其拆分成自己的 class。然后你也可以注入 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>
注入 class:
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(...);
}
}
您可以这样做,但它确实依赖于传递上下文,但您不必传递集合。这假设您正在过滤根 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,请参阅前面的 question/answer。 Can you get the DbContext from a DbSet?
这个有效
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
}
这可能吗?
Is that possible at all?
是的。
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
}
HOWEVER, the implementation detail queries other entities from the context, so an instance of the context is required in the method.
是的(有点,扩展方法然后脱离了 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();
这很丑陋,因为在此语句中返回的内容并不十分清楚。
不要硬塞进扩展方法中。它看起来像一个存储库模式或任何你想命名的。
因此,无论如何您都需要将其拆分成自己的 class。然后你也可以注入 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>
注入 class:
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(...);
}
}
您可以这样做,但它确实依赖于传递上下文,但您不必传递集合。这假设您正在过滤根 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,请参阅前面的 question/answer。 Can you get the DbContext from a DbSet?