2015-06-10 3 views
3

В этом кодеEF6: Почему граф возвращает 0, но возвращает возврат элемента?

using (var db = new DbPerson()) 
{ 
    var b = db.People.Create(); 
    b.Name = "Homer"; 

    db.People.Add(b); 

    Console.WriteLine("Count: {0}", db.People.Count()); 

    foreach (var bb in db.People) 
     Console.WriteLine(bb.Name); 

    var fb = db.People.Find(b.Id); // Id is a GUID generated in the Person ctor 
            // NOT a DB-generated Identity. 
    Console.WriteLine("Found: {0}", fb != null); 

    db.SaveChanges(); 

    Console.WriteLine("Count: {0}", db.People.Count()); 
} 

выход выглядит следующим образом:

Count: 0 
Found: True 
Count: 1 

Я видел другие сообщения о графе не обновляются до тех пор, пока SaveChanges называется. Хорошо, так что это «способ, которым это работает».

Мой вопрос конкретно: Почему Find возвращает объект из db.People, когда Count() возвращает 0, и перечислитель не возвращает никаких элементов? Не должно Find и Count() действовать аналогично, ожидая SaveChanges перед возвратом Сущности, находящиеся в состоянии «Добавлено»?

Какова причина этого? Я спрашиваю, потому что я пишу легкий не-SQL-провайдер, который должен максимально отражать действия EF. Я не могу понять, какая логика вызывает Find, чтобы вернуть добавленный элемент, который Count() и GetEnumerator() этого не делает. Мне нужно решать эти ситуации.

ответ

1

Find() имеет особое качество: сначала он будет изучать сущности DbContext, которые были недавно добавлены, но еще не сброшены в базу данных (например, объекты с EntityState.Added).

Count() и перечислитель вместо этого посмотрит на базу данных, которая, очевидно, еще ничего не сообщит, пока вы не позвоните SaveChanges().

Background info

+0

Я полностью понимаю это. Мой вопрос: почему, и где еще мне нужно знать, что новые добавленные объекты контекста ищутся/включены, а где нет? – Veldaeven

+1

Каждый раз, когда вы получаете неожиданные результаты, я предполагаю? Например, это было также объяснено в [docs] (https://msdn.microsoft.com/en-us/library/gg696418 (v = vs.113) .aspx): «* Если объект с данным первичным ключом Значения существуют в контексте, затем он немедленно возвращается без запроса в хранилище. * " –

+0

После прочтения документов по каждому методу в' DbSet <> ', а также для проверки таких вещей, как использование Queryable.FirstOrDefaulit' на 'DbSet', я думаю, что это ответ. Метод Find - это единственное место, где он явно указывает, что возвращаемые значения взяты из контекста, а не из базы данных. 'FirstOrDefault' не будет« находить »объект до момента сохранения изменений. – Veldaeven

1

Если вы спросите, почему это реализовано так: Find должен позволить вам получить доступ отслеживаемых объектов по идентификатору, которые отсутствуют в базе данных. Find - довольно специальный метод. Возможно, он позволяет извлекать удаленные объекты, а документы не говорят. There are other APIs for reaching into the pool of tracked entities as well.

Обычно это признак плохого использования EF (или признака взлома), если вам нужно возиться с этим.

NHibernate был очень полезным Find: Он позволил вам получить объект без, идущий в базу данных. Он возвращает прокси. Таким образом, вы всегда можете передавать объекты объектов и почти никогда не ID. Хорошая абстракция. Это невозможно с EF. Find идет в базу данных.

+0

Я только что протестировал его. Объект, который был удален (до SaveChanges, в состоянии «Удалено») также будет возвращен Find. – Veldaeven

+0

Btw, NHibernate было приятно в другом отношении.Он автоматически сохранял все изменения перед каждым запросом. Таким образом, база данных всегда была синхронизирована, и было сложно определить разницу между результатами контекста и результатами db. Девизом NHibernate было упорство в невежестве. – usr

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