EntityFramework CTP5更改跟踪

时间:2011-02-10 21:48:14

标签: entity-framework poco entity-framework-ctp5

我正在尝试使用CTP5 DBContext重现与EntityObject相同的行为以进行更改跟踪。考虑表Movie和Director。关系只有一个电影导演和每个导演的多部电影。

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中那样编写“Association fixup”逻辑?
  • 如果是这样,为什么在DbContext T4生成器中删除了协会修正代码?

2 个答案:

答案 0 :(得分:1)

当然新导演没有得到保存,因为您在代码的某个稍后时间点将新影片的导演更改为现有导演,试试这个导演并将它们保存到数据库中:

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将被添加。但是,即使您使用POCO代理(即使您的导航属性为虚拟),也不会实现此关系跨度行为。

答案 1 :(得分:0)

我认为这不符合你期望的原因是你正在创建一个Movie类本身的实例(即使用new运算符),而不是动态代理。 Movie类本身没有内置的更改跟踪。因此,当您设置Director属性时,不会向DbContext发送任何通知。即使您将电影添加到DbContext,您仍然引用原始对象,而不是代理。我想如果你使用DbSet.Create()(http://msdn.microsoft.com/en-us/library/gg696685(v=vs.103).aspx)创建了这个对象,那就行了。