2013-12-03 3 views
1

Я работаю с Entity Framework - Code First, и у меня есть следующий контекст (экстракции по крайней мере):Entity Framework: Фильтрующие свойства навигации

public class TestContext : DbContext 
{ 
    public DbSet<User> Users { get; set} 
    public DbSet<Book> Books { get; set} 
} 

А в классе пользователя у меня есть это свойство навигации:

public virtual Collection<Book> Books { get; set} 

ergo, пользователь имеет много книг. Проблема в том, что я хочу отфильтровать книги, но поскольку у меня есть около 500 000 книг в моей базе данных, я не могу позволить себе приносить все книги в память и фильтровать их позже. Мне нужно выполнить запрос к базе данных с предложением фильтра.

Когда я это сделать:

// Doesn't matter how i get the user... 
var allBooks = user.Books; // Here it brings all the books of the user 
var activeBooks = allBooks.Where(n => n.Active); 

Я думаю, что вы можете увидеть проблему ... я хочу добавить к запросу фильтры перед выполнением ... но я не знаю, как я могу сделать что.

Буду признателен за любой совет.

Спасибо.

EDIT:

Другой пример с явным контексте, может быть, это убрать вещи ...

IQueryable<Course> query = new TestContext().Set<User>(); // It doesn't run the query yet. 
var a = query.Where(n => n.Active); // Here it runs the query! 
var b = a.ToList(); // The items was on memory... 

ответ

1

Я лично не вижу никаких проблем с тем, что вы делаете. Список книг не будет загружен в память до тех пор, GetEnumerator(), либо явно, либо путем вызова Еогеасп и т.д ..

var activeBooks = user.Books.Where(n => n.Active); //still iqueryable 
var inMemory = activeBooks.ToList(); //executes iqueryable 
//or 
foreach(var book in activeBooks) 
    { 

    } 

Редактировать

вы можете прочитать на IQueryable http://msdn.microsoft.com/en-us/library/system.linq.iqueryable(v=vs.110).aspx

«Интерфейс IQueryable наследует интерфейс IEnumerable, так что если он представляет запрос, результаты этого запроса могут быть перечислены. Перечисление заставляет дерево выражений, связанное с объектом IQueryable, выполняться. Определение «выполнение дерева выражений» относится к поставщику запросов. Например, он может включать перевод дерева выражений на соответствующий язык запросов для базового источника данных. Запросы, которые не возвращают перечисляемые результаты выполняются, когда метод Execute вызывается «.

Это означает, что для того, чтобы выполнить запрос, который вы должны перечислить перечислимое.

IQueryable<Course> query = new TestContext().Set<User>(); // It doesn't run the query yet. 

IQueryable<Course> a = query.Where(n => n.Active); // Not executed yet 

IQueryable<Course> c = a.Where(n => n.Title.Contains("Science")); //still not executed 

List<Course> b = a.ToList(); //Executes the query 
+0

Да, я знаю, что это так, но я проверяю intelltrace на VS, и запрос выполняется, когда я получаю доступ к свойству навигации. В вашем примере пользователь.Books привезет все книги, а затем «где» будет фильтровать их в памяти ... –

+0

Я добавил еще один пример ... проверьте его, может быть, он что-то очищает .. . –

+0

Спасибо! Он решен! но теперь у меня есть еще одна проблема ... Свойства навигации ... проверьте это: http://stackoverflow.com/questions/20357511/entity-framework-naviogation-properties-issue –

0

Используйте filtered explicit loading, чтобы загрузить Нужные книги:

dbContext.Entry(user).Collection(u => u.Books).Query().Where(b => b.Active).Load(); 
0

Я реализовал решение, которое участвует оберточной IDbSet и использовать его вместо обычных членов контекста, как это:

public class MyContext : DbContext 
{ 
    public IDbSet<MyEntity> Entities { get; set; } 

    public MyContext() 
    { 
     this.Entities = new FilteredDbSet<MyEntity>(this, x => x.SomeProperty == 1); 
    } 
} 

Класс FilteredDbSet автоматически добавляет выражение, переданное конструктору ко всем запросам для этого объекта.См. Мой пример: http://weblogs.asp.net/ricardoperes/filter-collections-automatically-with-entity-framework-code-first.

Смежные вопросы