I'm trying to remove a child entity from a parent collection navigation property. There is a one-to-many relationship set up b/t parent and child. Once I remove the child, I want the database to remove the assoc. child record from the database rather than orphaning that record by nullifying the foreign key.
Is there any way to do this without having to explicitly delete the child via the child DbSet in the DBContext?
I've seen other posts related to this topic, but I thought I'd distill the code down to a simpler test case:
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);
}
}
}