Поиск контекстов Entity Framework

Через различные вопросы, которые я задавал здесь и на других форумах, я пришел к выводу, что я понятия не имею, что я делаю, когда дело доходит до сгенерированных объектов контекста сущности в Entity Framework.

В качестве фона у меня есть огромный опыт использования LLBLGen Pro, а Entity Framework для меня около трех недель.

Допустим, у меня есть контекст под названием «myContext». В моей модели есть таблица/объект с именем Employee, поэтому теперь у меня есть myContext.Employees. Я предполагаю, что это означает, что это свойство представляет набор сущностей Employee в моем контексте. Однако я предполагаю, что это неправильно, так как я могу добавить новую сущность в контекст с помощью:

myContext.Employees.AddObject(new Employee());

и этот новый объект Employee нигде не появляется в myContext.Employees. Из того, что я понял, единственный способ найти этот недавно добавленный объект — отследить его скрытие в myContext.ObjectStateManager. Мне кажется, что набор myContext.Employees на самом деле является не набором сущностей Employee в контексте, а скорее неким представлением сущностей Employee, которые существуют в базе данных.

Чтобы добавить еще больше этой путаницы, допустим, я смотрю на одну сущность Employee. Существует объект Project, который имеет связь M:1 с Employee (сотрудник может иметь несколько проектов). Если я хочу добавить новый проект конкретному сотруднику, я просто делаю:

myEmployee.Projects.Add(new Project());

Отлично, это действительно добавляет проект в коллекцию, как я и ожидал. Но это идет вразрез с тем, как работают свойства ObjectSet вне контекста. Если я добавлю новый проект в контекст с помощью:

myContext.Projects.AddObject(new Project());

это не изменяет набор проектов.

Я был бы очень признателен, если бы кто-нибудь объяснил мне это. Кроме того, мне действительно нужна коллекция всех сотрудников (или проектов) в контексте, и я хочу, чтобы она была доступна как свойство контекста. Возможно ли это с EF?


person Mike Gates    schedule 26.04.2010    source источник


Ответы (1)


ObjectSet — это запрос. Как и все в LINQ, это лениво. Он ничего не делает, пока вы не перечислите его или не вызовете метод, подобный .Count(), после чего запускается запрос к базе данных, и все возвращаемые объекты объединяются с теми, которые уже находятся в контексте.

Итак, вы можете сделать что-то вроде:

var activeEmployees = Context.Employees.Where(e => e.IsActive)

... без запуска запроса.

Вы можете дополнительно составить это:

var orderedEmployees = activeEmployees.OrderBy(e => e.Name);

...опять же, без выполнения запроса.

Но если посмотреть на набор:

var first = orderedEmployees.First();

...затем выполняется запрос к БД. Это общее для всех LINQ.

Если вы хотите перечислить объекты уже в контексте, вам нужно вместо этого смотреть на ObjectStateManager. Итак, для сотрудников вы можете сделать следующее:

var states = EntityState.Added || EntityState.Deleted || // whatever you need
var emps = Context.ObjectStateManager.GetObjectStateEntries(states)
                                     .Select(e => e.Entity)
                                     .OfType<Employee>();

Обратите внимание, что хотя это работает, я бы не рекомендовал работать таким образом. Как правило, вы не хотите, чтобы ваши ObjectContexts были долговечными. По этой и другим причинам они не совсем подходят для использования в качестве контейнера объектов общего назначения. Используйте для этого обычные типы списка. Правильнее думать об ObjectContext как о единице работы. Как правило, в единице работы вы уже знаете, с какими экземплярами вы работаете.

person Craig Stuntz    schedule 26.04.2010
comment
Это идея, которую я начал получать. Эти свойства в контексте (например, .Employees) предназначены не для управления состоянием, а для запросов к БД. Тот факт, что они есть, делает контекст не похожим на единицу работы, а скорее на своего рода контейнер данных. Итак, не могли бы вы предложить в приложении создавать и использовать мои собственные контейнеры данных? Например, ObservableCollection‹Employee›, где я сам отслеживаю изменения? - person Mike Gates; 27.04.2010
comment
Пусть ObjectContext отслеживает изменения. Но если вам нужен список активных сотрудников и вы не хотите каждый раз запрашивать БД, обязательно используйте List или аналогичный. Просто поймите, что если список переживает контекст, вам придется отсоединиться и присоединиться, прежде чем вы сможете использовать объект в обновлении, поэтому часто проще (и достаточно быстро) просто запросить еще раз. Политику кэширования сложно настроить правильно. - person Craig Stuntz; 27.04.2010
comment
Правильно, поэтому список необходимо синхронизировать с ObjectContext. Таким образом, добавление/удаление из списка приводит к добавлению/удалению в ObjectContext и наоборот. Чувак, это больно подключать ... хотелось бы, чтобы в Microsoft было встроено что-то подобное. - person Mike Gates; 27.04.2010
comment
Опять же, если вы действительно делаете это, у вас есть большие проблемы. Пересмотрите ObjectContext, чтобы вы не использовали один и тот же контекст для отображения и обновления. Опять же, подумайте об этом как о единице работы. - person Craig Stuntz; 27.04.2010
comment
Это для приложения WPF. Если пользователь выполняет добавление на одном экране, удаление на другом экране и пару обновлений на другом экране, а затем нажимает «Сохранить», все эти действия должны отслеживаться непрерывной единицей работы (иначе мне нужно создать еще одно пользовательское изменение). следящий механизм). Поэтому мне нужно сохранять ObjectContext между сохранениями. Поэтому мне нужно, чтобы этот ObjectContext синхронизировался с моими контейнерами данных (список сотрудников или что-то еще) ... Это если я не подхожу к этому совершенно неправильно (?). - person Mike Gates; 27.04.2010
comment
Используйте шаблон MVC или MVVM. Создайте модель редактирования по мере того, как пользователь просматривает экраны, а затем отправьте все это в одном действии обновления. Контекст длится только до тех пор, пока выполняется обновление, потому что это ваша единица работы. Другие единицы работы заполняют каждый экран. - person Craig Stuntz; 27.04.2010
comment
Этот вопрос и ответы читаются несколько запутанно, если читатель представляет контекст, производный от DbContext, и DbSet‹Employees›. С этими более поздними дополнениями к Entity Framework поведение соответствует ожиданиям спрашивающего. Вызов context.Employees.Add(new Employee()) действительно сделает этого нового сотрудника доступным в DbSet сотрудников. - person Josh Gallagher; 04.02.2014