我正在尝试使用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个问题。
答案 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)创建了这个对象,那就行了。