I've a thread which contains a startpost as part of the thread-content. It also includes a list of replys, which are also posts.
class Post {
[Key]
public int Id{get;set;}
public DateTime CreationDate{get;set;}
public virtual string Content{get;set;}
public int ThreadId{get;set;}
public virtual Thread Thread{get;set;}
}
class Thread {
[Key]
public int Id{get;set;}
public string Title{get;set;}
public int FirstPostId{get;set;}
public virtual Post FirstPost{get;set;}
public List<Post> Replys{get;set;}
}
When a thread is created i simply add them to the DbContext and save it. This works without issues. But if a reply is submitted, I add them to the post-list and mark the entity of the thread as modified like this
var db = new MyContext();
var thread = db.Threads.Where(thread => thread.Id = threadId).FirstOrDefault();
thread.Replys.Add(newPost);
db.Entry<Thread>(thread).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
Here is the problem that I get a violation of the foreignkey on Thread.FirstPost:
Cannot add or update a child row: a foreign key constraint fails ("MyTable"."posts", CONSTRAINT "Thread_FirstPost" FOREIGN KEY ("Id") REFERENCES "threads" ("Id") ON DELETE NO ACTION ON UPDATE NO ACTION)
I found many information about this. In short, all say, that this is related to the default behavior of EF that checks the integrity. So when a Thread has to be deleted it depends on the FirstPost which has also to be deleted but this depends on the Thread which seem to confuse EF.
The internet has 2 solutions for this problem: Using fluent-API to disable cascade for the entity using .WillCascadeOnDelete(false);
or disable it completely by removing the convention. I tried both ways:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
//base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Thread>()
.HasOptional(t => t.FirstPost)
.WithRequired()
.WillCascadeOnDelete(false);
modelBuilder.Entity<Post>()
.HasOptional(p => p.Thread)
.WithMany()
.HasForeignKey(p => p.ThreadId)
.WillCascadeOnDelete(false);
}
But nothing is working, I get the same exception than before. I have no idea why, and it seems that all others which had this problem could solve it by using one of those methods, but in my case both have no effect...
Table-Definitions from Visual Studio Server-Explorer
CREATE TABLE `posts` (
`Id` int(11) NOT NULL,
`CreationDate` datetime NOT NULL,
`Content` longtext NOT NULL,
`ThreadId` int(11) NOT NULL,
PRIMARY KEY (`Id`),
KEY `ThreadId` (`ThreadId`),
CONSTRAINT `Thread_Post` FOREIGN KEY (`Id`) REFERENCES `threads` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Thread_Replys` FOREIGN KEY (`ThreadId`) REFERENCES `threads` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `threads` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Title` longtext NOT NULL,
`PostId` int(11) NOT NULL,
`ViewsCount` int(11) NOT NULL,
`IsClosed` tinyint(1) NOT NULL,
`IsVisible` tinyint(1) NOT NULL,
`ReplysCount` int(11) NOT NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `Id` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Table-Definition generated by EF (from Database-Server)
CREATE TABLE `Posts`(
`Id` int NOT NULL,
`CreationDate` datetime NOT NULL,
`Content` longtext NOT NULL,
`ThreadId` int NOT NULL
)
ALTER TABLE `Posts` ADD PRIMARY KEY (Id)
ALTER TABLE `Posts` ADD CONSTRAINT Thread_Post
ALTER TABLE `Posts` ADD KEY (`ThreadId`)
ALTER TABLE `Posts` ADD CONSTRAINT Thread_Replys
ALTER TABLE `Posts` ADD CONSTRAINT Thread_Post
FOREIGN KEY (Id)
REFERENCES `Threads` (Id)
ALTER TABLE `Posts` ADD CONSTRAINT Thread_Replys
FOREIGN KEY (ThreadId)
REFERENCES `Threads` (Id)
ALTER TABLE `Posts` ADD CONSTRAINT Thread_Replys
FOREIGN KEY (ThreadId)
REFERENCES `Threads` (Id)
ON DELETE NO ACTION ON UPDATE NO ACTION
CREATE TABLE `Threads`(
`Id` int NOT NULL AUTO_INCREMENT UNIQUE,
`Title` longtext NOT NULL,
`PostId` int NOT NULL,
`ViewsCount` int NOT NULL,
`IsClosed` bool NOT NULL,
`IsVisible` bool NOT NULL,
`ReplysCount` int NOT NULL
)
ALTER TABLE `Threads` ADD PRIMARY KEY (Id)
Here are some pages I found on my research to this topic: http://weblogs.asp.net/manavi/associations-in-ef-code-first-ctp5-part-3-one-to-one-foreign-key-associations
http://www.codeproject.com/Articles/368164/EF-Data-Annotations-and-Code-Fluent
http://geekswithblogs.net/danemorgridge/archive/2010/12/17/ef4-cpt5-code-first-remove-cascading-deletes.aspx
http://patrickdesjardins.com/blog/entity-framework-4-3-delete-cascade-with-code-first-poco
ASP.NET MVC 4 Multiple Foreign Keys Referencing Single Parent Entity
http://www.davepaquette.com/archive/2012/09/15/whered-my-data-go-andor-how-do-i-get-rid-of-it.aspx
http://czetsuya-tech.blogspot.de/2012/01/specify-on-delete-no-action-or-on.html#.Viy-0X54u9J
Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?
Entity Framework: how to solve "FOREIGN KEY constraint may cause cycles or multiple cascade paths"?
Specify ON DELETE NO ACTION in ASP.NET MVC 4 C# Code First