EF 4.1 CodeFirst - 一对多级联删除

dro*_*gon 3 one-to-many ef-code-first entity-framework-4.1

我正在尝试从父集合导航属性中删除子实体.b/t父母和孩子之间建立了一对多的关系.删除子项后,我希望数据库删除assoc.来自数据库的子记录,而不是通过使外键无效而孤立的记录.

有没有办法做到这一点,而无需通过DBContext中的子DbSet显式删除子进程?

我已经看到了与此主题相关的其他帖子,但我想我会将代码提炼为更简单的测试用例:

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using NUnit.Framework;

namespace basic_tests
{
[TestFixture]
public class OneToManyTests
{
    #region Setup/Teardown

    [SetUp]
    public void SetUp()
    {
        _context = new Context();
        Database.SetInitializer(new DataInitializer());
    }

    #endregion

    private Context _context;

    [Test]
    public void CanRemoveChildThroughParent()
    {
        /**

        this throws : "System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while saving entities that do not expose foreign key properties for              their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of               exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for                  
         details.System.Data.UpdateException : A relationship from the 'Child_MyParent' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a 
         corresponding 'Child_MyParent_Source' must also in the 'Deleted' state.

         **/

        var parent = _context.Parents.FirstOrDefault();
        var firstChild = parent.MyChildren.FirstOrDefault();
        parent.MyChildren.Remove(firstChild);

        _context.SaveChanges();

        var parentRefresh = new Context().Parents.FirstOrDefault();
        Assert.AreEqual(1, parentRefresh.MyChildren.Count);

        var childrenCount = new Context().Children.Count();
        Assert.AreEqual(1, childrenCount);
    }
}

public class Parent
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Child> MyChildren { get; set; }
}

public class Child
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Parent MyParent { get; set; }
}

public class Context : DbContext
{
    public DbSet<Parent> Parents { get; set; }
    public DbSet<Child> Children { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Child>()
            .HasRequired(c => c.MyParent)
            .WithMany(p => p.MyChildren)
            .WillCascadeOnDelete(true);
    }
}

public class DataInitializer : DropCreateDatabaseAlways<Context>
{
    protected override void Seed(Context context)
    {
        for (var i = 0; i < 2; i++)
        {
            context.Children.Add(new Child
                                     {
                                         Name = "child" + i
                                     });
        }

        var parent = new Parent { Name = "parent", MyChildren = context.Children.Local.ToList() };

        context.Parents.Add(parent);

        base.Seed(context);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

Sla*_*uma 5

有没有办法做到这一点,而无需通过DBContext中的子DbSet显式删除子进程?

在你的模型中:不,没有别的办法.你必须打电话:

var parent = _context.Parents.FirstOrDefault();
var firstChild = parent.MyChildren.FirstOrDefault();
_context.Children.Remove(firstChild);

_context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

我最近了解到,当您从父集合中删除子项时,有一个例外会导致数据库中的自动删除.这就是所谓的Identifying关系,它要求子节点中引用父节点的外键属性必须是子节点的(复合)主键的一部分:

public class Child
{
    [Key, Column(Order = 0)]
    public virtual int Id { get; set; }
    [Key, ForeignKey("MyParent"), Column(Order = 1)]
    public virtual int MyParentId { get; set; }

    public virtual string Name { get; set; }
    public virtual Parent MyParent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您的代码确实会从数据库中删除子代.这里解释(最后一节在底部):http://msdn.microsoft.com/en-us/library/ee373856.aspx