I've created a many to many relationship using default conventions in EF CTP4 by defining an ICollection on both image and project entities.
The mapping table is created as below:
create table [dbo].[Images_Project] (
[Images_Id] [uniqueidentifier] not null,
[Project_Id] [uniqueidentifier] not null,
primary key ([Images_Id]));
Unfortunately when I delete a project it is not cascading deletes to the image mapping table.
I would expect EF to generate a key on both the Imanges_Id and Project_Id properties but this is not the case. How can I configure EF to delete the image mappings when a project is deleted? (only the image mapping record, not the image record)
Thanks
[Update]
Although cascade is apparently not possible, any idea why the following test passes:
[Test]
public void Can_delete_project_with_images()
{
var project = new Project { Title = "Test project" };
var image = new Image { Title = "Some image" };
project.AddImage(image);
context.Set<Project>().Add(project);
context.SaveChanges();
object id = project.Id;
object imageId = image.Id;
var fromDb = context.Projects.Find(id);
fromDb.ShouldNotBeNull();
context.Set<Project>().Remove(fromDb);
context.SaveChanges();
var fromDb2 = context.Images.Find(imageId);
fromDb2.ShouldNotBeNull();
fromDb2.Title.ShouldEqual("Some image");
}
As of EF CTP4, there is no way to directly turn on cascade deletes on Many to Many associations in fluent API. The only way to have that is to explicitly put the link table into the object model:
public class Project
{
public int Id { get; set; }
public ICollection<ProjectXrefImage> Images { get; set; }
}
public class ProjectXrefImage
{
[Key][DataMember(Order = 1)]
public int ProjectId { get; set; }
[Key][DataMember(Order = 2)]
public int ImageId { get; set; }
public Project Project { get; set; }
public Image Image { get; set; }
}
public class Image
{
public int Id { get; set; }
public virtual ICollection<ProjectXrefImage> Projects { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Project> Projects { get; set; }
public DbSet<Image> Images { get; set; }
public DbSet<ProjectXrefImage> ProjectsXrefImages { get; set; }
}
That said, I personally would not do this and will manually turn them on in the database.
Update:
As you discovered it through your test case, code first will take care of cascade delete on the client side even though it's not turned on on the data store. Which means, when you delete a Project by invoking Remove() method, code first is smart enough to first send a delete statement to get rid of the dependent record from the link table (Images_Projects) and after that it will send another delete statement to delete the project record. I've verify that with SQL Profiler.
That's why we can't turn on cascade deletes on many to many relationships, because we don't need it! The convention that I explained above will take care of that for us!
SQL Server does not allow you to have cyclic cascading deletes.