2017-02-10 2 views
2

Это работаетIQueryable метод расширения без прохождения DbContext в качестве параметра

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 
} 

Возможно ли это вообще?

ответ

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 непосредственно и получить DbContext от этого DbSet затем посмотреть предыдущий вопрос/ответ. 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 
} 

ОДНАКО, детали реализации запросов другие объекты из контекста, поэтому экземпляр контекста требуется в методе.

Да (Сорта, метод расширения затем от 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(); 

Это некрасиво, потому что это не совсем понятно, в этом что возвращается.

+0

Извините, возможно, я не сделал вопрос достаточно ясным: я уже реализовал его, как вы описали, ОДНАКО, деталь реализации запрашивает другие объекты из контекста, поэтому в этом методе необходим экземпляр контекста. –

+0

Вы просто спросили, как это сделать без контекста, затем в этом комментарии вы указываете, что необходим контекст ... что это? –

+0

Я никогда не говорил, что контекст не требуется. Напротив, мой вопрос задает вопрос о том, как структурировать метод расширения без необходимости ПРОСМОТР контекста (мне он все еще нужен). –

-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(...); 
    } 
} 
Смежные вопросы