Отслеживание изменений EntityFramework CTP5

Я пытаюсь воспроизвести то же поведение, что и EntityObject, используя CTP5 DBContext для отслеживания изменений. Рассмотрим таблицы Movie и Director. Отношения - это только 1 режиссер для фильма и несколько фильмов для каждого режиссера.

var movie = new Movie();
            movie.Name = "ABCD";
            ctx.Movies.Add(movie);//ctx.Movies.AddObject(movie); 
            movie.Director = new Director() { Name = "dir1" };
            var existingDirector = ctx.Directors.Where(a => a.Name == "dir2").FirstOrDefault();
            movie.Director = existingDirector;
            ctx.SaveChanges();

Если я запущу это с помощью EntityObject, этот код создаст новый директор «dir1» по мере отслеживания изменений. Если я запускаю этот код с помощью генератора CTP 5 DbContext, новый директор «dir1» не создается. Я изменил свойства на виртуальные как в объектах Movie, так и в Director. Ниже приведен код.

public partial class Director
{
    public Director()
    {
        //this.Movies = new HashSet<Movie>();
    }

    // Primitive properties

    public virtual int DirectorId { get; set; }
    public virtual string Name { get; set; }

    // Navigation properties

    public virtual ICollection<Movie> Movies { get; set; }

}
public partial class Movie
{
    public Movie()
    {
        //this.Actors = new HashSet<Actor>();
    }

    // Primitive properties

    public virtual int MovieId { get; set; }
    public virtual Nullable<int> DirectorId { get; set; }
    public virtual string Name { get; set; }

    // Navigation properties

    public virtual Director Director { get; set; }    
}

У меня есть 3 вопроса.

  • Я что-то пропустил здесь? Несмотря на то, что я сохранил «виртуальный» для каждого свойства, объект не отслеживается. Почему?
  • Должен ли я писать логику «Исправление ассоциации», как это было сделано в EF4 POCO?
  • Если да, то почему код исправления ассоциации был удален в генераторе DbContext T4?

person Jonna    schedule 10.02.2011    source источник


Ответы (2)


Конечно, новый режиссер не сохраняется, потому что вы изменили режиссера нового фильма на существующего в какой-то более поздний момент вашего кода, попробуйте этот, и вы сохраните их обоих в БД:

var movie = new Movie();
movie.Name = "ABCD";
ctx.Movies.Add(movie);
movie.Director = new Director() { Name = "dir1" };    
//movie.Director = existingDirector;
ctx.SaveChanges();

Вы можете написать свою собственную логику исправления ассоциации, но она позаботится о синхронизации конечных точек ваших ассоциаций и не имеет ничего общего с кодом, который вы показали здесь.

Причина, по которой ваш код сохраняет новый директор в БД при использовании EntityObjects, связана с концепцией, которая называется Relationship Span. Диапазон отношений определяет, что ObjectContext будет автоматически присоединять объект, когда вы присоединяете его к другому присоединенному объекту. Если этот отсоединенный объект новый, когда он присоединен к контексту, его EntityState будет добавлен. Однако это поведение Relationship Span не реализуется, даже если вы используете прокси-серверы POCO (т. е. делаете ваши свойства навигации виртуальными).

person Morteza Manavi    schedule 10.02.2011
comment
Код тупой, но я хотел показать несоответствие между генераторами EntityObject и DbContext T4. Дело в том, что с генератором EntityObject тот же код (без комментирования строки) создает dir1 в db, тогда как генератор POCO или DbContext этого не делает. Почему? Что случилось с отслеживанием изменений? - person Jonna; 11.02.2011

Я думаю, что причина того, что это не работает так, как вы ожидаете, заключается в том, что вы создаете экземпляр самого класса Movie (т.е. используя новый оператор), а не динамический прокси. Сам класс Movie не имеет встроенного отслеживания изменений. Следовательно, когда вы устанавливаете свойство Director, в DbContext не отправляется уведомление. Несмотря на то, что вы добавили фильм в DbContext, вы по-прежнему ссылаетесь на исходный объект, а не на прокси. Я думаю, что если бы вы создали объект с помощью DbSet.Create() (http://msdn.microsoft.com/en-us/library/gg696685(v=vs.103).aspx), это сработало бы.

person Jon Miller    schedule 30.04.2012