2015-01-12 3 views
0

Недавно я spoted странного поведения в EntityFramework 6, учитывая следующую программу может кто-нибудь объяснить мне, почемуEntity Framework - назначение список поведение

parent.Children = new List<ChildObject> { new ChildObject("newChild", "newValue") }; 

фактически добавляет нового ребенка в список детей вместо удаления старого детей и добавления новых.

Использование db.Parents.Include(x => x.Children).First() для загрузки родителя решает проблему, что делает это поведение даже незнакомое ...

Были ли это сознательный выбор дизайна или это на самом деле ошибка?

Полная программа испытаний:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Data.Entity; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace EF_PlayWithList 
{ 
    public class ChildObject 
    { 
     public int Id { get; protected set; } 

     public int ParentId { get; protected set; } 
     public string Name { get; protected set; } 
     public string Value { get; protected set; } 

     protected ChildObject() { } 

     public ChildObject(string name, string value) 
     { 
      this.Name = name ?? ""; 
      this.Value = value ?? ""; 
     } 

     public override string ToString() 
     { 
      return string.Format("{0}: {1}", this.Name, this.Value); 
     } 
    } 

    public class ParentObject 
    { 
     public int Id { get; protected set; } 
     public string Name { get; protected set; } 

     public virtual IList<ChildObject> Children { get; set; } 

     protected ParentObject() { } 

     public ParentObject(string name) 
     { 
      this.Name = name; 
      this.Children = new List<ChildObject>(); 
     } 

     public void AddChild(ChildObject child) 
     { 
      this.Children.Add(child); 
     } 

     public override string ToString() 
     { 
      return string.Format("Parent '{0}' with {1} childs.", this.Name, this.Children.Count); 
     } 
    } 

    class TestDbContext : DbContext 
    { 
     public DbSet<ParentObject> Parents { get; set; } 

     public TestDbContext() 
      : base() 
     { 

     } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      modelBuilder.Entity<ParentObject>() 
       .HasMany(x => x.Children) 
       .WithRequired() 
       .HasForeignKey(x => x.ParentId) 
       .WillCascadeOnDelete(); 

      modelBuilder.Entity<ParentObject>() 
       .HasKey(x => x.Id); 

      modelBuilder.Entity<ParentObject>() 
       .Property(x => x.Id) 
       .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

      modelBuilder.Entity<ChildObject>() 
       .HasKey(x => new { x.Id, x.ParentId }); 

      modelBuilder.Entity<ChildObject>() 
       .Property(x => x.Id) 
       .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Database.SetInitializer(new DropCreateDatabaseAlways<TestDbContext>()); 

       using (var db = new TestDbContext()) 
       { 
        var parent = new ParentObject("superFooParent"); 
        parent.AddChild(new ChildObject("foo", "1")); 
        parent.AddChild(new ChildObject("bar", "2")); 

        db.Parents.Add(parent); 
        db.SaveChanges(); 
       } 

       using (var db = new TestDbContext()) 
       { 
        var parent = db.Parents.First(); 

        parent.Children = new List<ChildObject> 
        { 
         new ChildObject("newChild", "newValue") 
        }; 

        db.SaveChanges(); 
       } 

       using (var db = new TestDbContext()) 
       { 
        foreach (var parent in db.Parents.Include(x => x.Children)) 
        { 
         Console.WriteLine(parent); 

         foreach (var child in parent.Children) 
         { 
          Console.WriteLine("\t{0}", child); 
         } 
        } 
       } 

      Console.ReadLine(); 
     } 
    } 
} 
+0

Вам нужно будет спросить команду дизайнеров EF, если это было намеренно, и если да, то почему они приняли это решение. Мы можем только догадываться. – Servy

+0

Как и выше, это было бы предположение, но я не думаю, что это плохо, что вы должны явно удалить все «Дети». Кроме того, вы могли бы открыть всевозможные проблемы с референциальной целостностью, если бы разрешили такую ​​замену. – barrick

+0

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

ответ

1

При вызове SaveChanges на вашем DbContext, структура проверяет все объекты , что знает о увидеть, что были изменены, добавлены, удалены, и т.д. ... Если старый список детей никогда не был загружен, а DbContext не знает о них, и они не будут удалены. Это намеченное поведение. Если вы хотите, чтобы фреймворк внес изменения в базу данных, вы должны разрешить DbContext загружать затронутые объекты; в противном случае вам понадобится использовать чистый SQL.

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