0

MVC 4 を立ち上げたばかりですが、アプリケーションでエラーが発生したため、修正に支援が必要です。

Author & Book テーブルがあります。Author テーブルは親であり、各著者に複数の本を関連付けることができます。

まだブックが割り当てられている著者を削除しようとするまで、すべてがうまく機能しています。その場合、SaveChanges() で次のようなエラーが表示されます。

DELETE ステートメントは、REFERENCE 制約 "FK_Book_Author" と競合しました。

エラーは完全に理にかなっていますが、単純に爆発するのではなく、アプリケーションがユーザーに適切なエラー メッセージを表示することを望みます。

子が関連付けられているレコードを削除したときにアプリケーションが爆発しないように、モデルでこの関係を定義するにはどうすればよいですか?

著者クラス

public partial class Author
{
    public Author()
    {
        this.Book = new HashSet<Book>();
    }

    [Key]
    public int AuthorId { get; set; }

    [Required]
    public string AuthorName { get; set; }

    public virtual Book Book { get; set; }
}

ブッククラス

public partial class Book
{
    [Key]
    public int BookId { get; set; }

    [Required]
    public string BookName { get; set; }

    [Required]
    [ForeignKey("Author")]
    public string AuthorId { get; set; }
}

モデル

最近、OnModelCreating をオーバーライドしようと試み始めましたが、効果がないようです。

public partial class BookEntities : DbContext
    {
        public BookEntities()
            : base("name=BookEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Book>().HasRequired(p => p.Author)
                .WithMany(b => b.Books)
                .HasForeignKey(p => p.AuthorId);

            modelBuilder.Entity<Author>()
                .HasMany(p => p.Books)
                .WithRequired(b => b.Author)
                .WillCascadeOnDelete(false);

            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        }

        public DbSet<Book> Books { get; set; }
        public DbSet<Author> Authors { get; set; }
    }

部分的な更新

  • これは、0..1 対多の関係に関する問題です。
  • 私は.edmxを使用しています。これにより、OnModelCreating メソッドが完全に無効になることがわかりました。
  • これがクラッシュするのをブロックするために、Linq ステートメントを DeleteConfirmed メソッドにスローできるようですが、私はそのアプローチが本当に好きではありません。
4

2 に答える 2

0

解決

この 1 つの問題に 1 日を費やした後、カスタム コードを DeleteConfirmed メソッドに挿入して、エラーの発生を防ぎ、このレコードを削除できないことをユーザーに警告することにしました。これはおそらく状況を処理するための最良の方法ではありませんが、機能的です。

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
    Author author = db.Authors.Find(id);

    // Count # of Books for this Author
    int count = (from book in db.Books
                        where book.BookId == id
                        select book.BookId).Count();

    // Prevent deletion of this record has any associated records
    if (count> 0)
    {
        TempData["errors"] = "Bad user! You can't delete this record yet!";
        return RedirectToAction("Delete");
    }
    else
    {
        db.Categories.Remove(category);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
}
于 2012-08-22T14:58:42.937 に答える
0

流暢な API も使用している場合は、通常、属性を使用しないため、このコードは完全に規約と流暢な API になります。

あなたの投稿は指定していませんが、古典的な book=>authors モデルは多対多の関係です。あなたのエンティティコードは、著者と本が正確に1つあると言っているようですが、流暢なコードは本と著者のコレクションがあることを暗示しているようです。

FWIW、ここに私が持っているものがあります:

public class Author
{
    public int AuthorId { get; set; }
    public string AuthorName { get; set; }

    public virtual ICollection<Book> Books { get; set; }
}

public class Book
{
    public int BookId { get; set; }
    public string BookName { get; set; }

    public virtual ICollection<Author> Authors { get; set; }
}

そしてオーバーライドで:

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Author>()
            .HasMany(a => a.Books)
            .WithMany(b => b.Authors)
            .Map(m =>
                {
                    m.ToTable("AuthorBooks");
                    m.MapLeftKey("AuthorId");
                    m.MapRightKey("BookId");
                });
}

これにより、次のデータベースが生成されます。

ここに画像の説明を入力

カスケードを取得するために必要なのはそれだけだと思います。慣例により、カスケードを実行する必要があります。

これがあなたが探していたものでない場合は投稿してください。

タル

于 2012-08-20T19:16:02.660 に答える