簡體   English   中英

ASP.NET MVC 5 EF無法添加或更新子行:外鍵約束失敗

[英]ASP.NET MVC 5 EF Cannot add or update a child row: a foreign key constraint fails

我有一個線程,其中包含一個startpost作為線程內容的一部分。 它還包括回復列表,這些列表也是帖子。

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;}
}

創建線程后,我只需將它們添加到DbContext並保存。 這沒有問題。 但是,如果提交了答復,則將其添加到帖子列表中,並將線程的實體標記為已修改,如下所示

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();

這是我在Thread.FirstPost上違反外鍵的問題:

無法添加或更新子行:外鍵約束失敗(“ MyTable”。“ posts”,CONSTRAINT“ Thread_FirstPost”外鍵(“ Id”)參考“線程”(“ Id”)刪除無操作更新無操作)

我發現了許多有關此的信息。 簡而言之,這與EF檢查完整性的默認行為有關。 因此,當必須刪除線程時,它取決於還必須刪除的FirstPost,但這取決於似乎使EF混淆的線程。

互聯網針對此問題提供了兩種解決方案:使用fluent-API使用.WillCascadeOnDelete(false);禁用實體的級聯.WillCascadeOnDelete(false); 或通過刪除約定將其完全禁用。 我嘗試了兩種方式:

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);
}

但是沒有任何效果,我得到了比以前相同的例外。 我不知道為什么,似乎所有其他有此問題的人都可以使用其中一種方法來解決它,但就我而言,這兩種方法都無效。

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

EF生成的表定義(來自數據庫服務器)

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)

這是我在研究此主題時發現的一些頁面: http : //weblogs.asp.net/manavi/associations-in-ef-code-first-ctp5-part-3-one-to-one-foreign-key -協會

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引用單個父實體的多個外鍵

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

引入FOREIGN KEY約束可能會導致循環或多個級聯路徑-為什么?

實體框架:如何解決“ FOREIGN KEY約束可能導致循環或多個級聯路徑”?

在ASP.NET MVC 4 C#代碼中首先指定ON DELETE NO ACTION

您的外鍵設置不正確,最好不要顯式定義外鍵,以防您使用原始類名,我將在代碼中進行解釋:

class Post {
    [Key]
    public int Id{get;set;}
    public DateTime CreationDate{get;set;}
    public virtual string Content{get;set;}
    public int ThreadId{get;set;}  **-> here you used ThreadId which is implicitly a foreignkey for Thread, and that's good**
    public virtual Thread Thread{get;set;}
}

class Thread {
    [Key]
    public int Id{get;set;}
    public string Title{get;set;}
    public int FirstPostId{get;set;} **-> here you can do the same by changing this to PostId**
    public virtual Post FirstPost{get;set;} **-> and this to Post**
    public List<Post> Replys{get;set;}
}

或者,您可以使用數據注釋的更好的選擇:

替換為:

 public virtual Post FirstPost{get;set;}

有了這個:

[ForeignKey("FirstPostId")]
public virtual Post FirstPost{get;set;}

這告訴EF FirstPostId是`FirstPost的外鍵。

讓我知道是否可行。

更新

我已經手動更改了您的sql代碼,現在可以使用:

CREATE TABLE threads (
  Id int NOT NULL,
  Title nvarchar(max) NOT NULL,
  PostId int,
  ViewsCount int NOT NULL,
  IsClosed tinyint NOT NULL,
  IsVisible tinyint NOT NULL,
  ReplysCount int NOT NULL,
  PRIMARY KEY (Id),
) 

CREATE TABLE posts (
  Id int NOT NULL,
  CreationDate datetime NOT NULL,
  Content nvarchar(max) NOT NULL,
  ThreadId int NOT NULL,
  PRIMARY KEY (Id),
  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
)

ALTER TABLE threads ADD CONSTRAINT Post_Thread FOREIGN KEY (PostId) REFERENCES posts (Id) ON DELETE NO ACTION ON UPDATE NO ACTION

您不能將線程定義為需要postID,也不能同時定義為post來要求threadID,如果那樣的話,您將無法創建兩者(除非您同時創建兩者-意味着在同一個db.savechanges( ))。

想一想。 您想使用尚不存在的帖子來定義線程。

根本問題是您的模型在PostThread之間包含1:1關聯,其中Thread是主要實體或獨立實體。 這由...部分表示

modelBuilder.Entity<Thread>()
    .HasOptional(t => t.FirstPost)
    .WithRequired()

您會看到它反映在DDL語句中...

ALTER TABLE `Posts` ADD CONSTRAINT Thread_Post
    FOREIGN KEY (Id)
    REFERENCES `Threads` (Id)

因此, Post's主鍵也是 Thread的外鍵。 這意味着每個Thread最多只能插入一個Post (因為每個后續的Post必須具有一個新的PK值,但這並不引用現有的Thread因此您會遇到約束違規的情況)。

您可以(使)以Post為主體來解決此問題。 在這種情況下, Thread將具有引用其第一個Post的PK / FK組合。 但是,對我而言,1:1關聯表示實體與它們幾乎是一個實體的點密切相關( Student - StudentDetails )。 因此,我認為1:1關聯並不適合。

我建議這種映射:

modelBuilder.Entity<Thread>()
    .HasOptional(t => t.FirstPost)
    .WithMany()
    .HasForeignKey(t => t.FirstPostId)
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Post>()
    .HasRequired(p => p.Thread)
    .WithMany(t => t.Replies)
    .HasForeignKey(p => p.ThreadId)
    .WillCascadeOnDelete(false);

從理論上講,這將ThreadFirstPost之間的關系變成一對多,但實際上這意味着Thread現在具有其第一個帖子的外鍵,並且這些復雜的PK / FK組合也消失了。 請注意, FirstPostId應為可為null的int來支持此功能。

在另一方面,如果在您看來,一個Thread和它的第一篇文章密切相關的,你可以考慮合並雙方進入一個線程,也有它的第一篇文章(屬性CreationDateContent )。 最后,您將獲得一個非常簡單的線程模型(帖子?),其中包含答復,但仍然沒有多余的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM