首先我的实际书籍和作者对象定义:
public class Book
{
[Key]
public virtual int BookID { get; set; }
[Required]
[DataType(DataType.Text)]
[MaxLength(100)]
public virtual String Title { get; set; }
[DataType(DataType.MultilineText)]
public virtual String Abstract { get; set; }
[RegularExpression(@"\d{4}")]
public virtual String Year { get; set; }
[Required]
[Display(Name="Genre")]
public virtual int GenreID { get; set; }
public virtual Genre Genre { get; set; }
public virtual List<Author> Authors { get; set; }
public Book()
{
Authors = new List<Author>();
}
}
public class Genre
{
[Key]
public virtual int GenreID { get; set; }
[Required]
[DataType(DataType.Text)]
[MaxLength(30)]
public virtual String Name { get; set; }
public virtual List<Book> Books { get; set; }
}
public class Author
{
[Key]
public virtual int AuthorID { get; set; }
[Required]
[DataType(DataType.Text)]
[MaxLength(50)]
public virtual String Firstname { get; set; }
[Required]
[DataType(DataType.Text)]
[MaxLength(50)]
public virtual String Lastname { get; set; }
public virtual List<Book> Books { get; set; }
public Author()
{
Books = new List<Book>();
}
[NotMapped]
public string Fullname
{
get { return String.Format("{0}, {1}", Lastname, Firstname); }
}
public override string ToString()
{
return Fullname;
}
}
使用EF-Migrations我得到一个configuration.cs文件,我在其中输入了Data-Seed,然后使用add-migration获得第一次迁移以初始化数据库EF正确创建了相应的表Authors,Books,Genres和last但并非最不重要的是,书籍能够保持书籍与作者之间的多对多关系。
到目前为止,我的整个演示应用程序正常运行。我唯一的问题是实体框架似乎拒绝保存AuthorBooks关系。我已经设置了我的应用程序,以便在书籍创建/编辑时我可以通过MultiSelectList-ListBox选择相关的作者。
BookControllerViewModel:
public class BookControllerViewModel
{
public Book actualBook { get; set; }
public String redirectUrl { get; set; }
public MultiSelectList Authors { get; set; }
public int[] AuthorIDs { get; set; }
public SelectList Genres { get; set; }
}
ViewModel包含受创建/编辑操作影响的书籍,作者的MultiSelectList以及基于书籍的正确Selection-Info,我添加了int [] AuthorIDs来保存用户在ListBox中选择的所选ID创建/编辑视图。
@model BookStoreInternet.ViewModels.BookControllerViewModel
<div class="editor-label">
@Html.LabelFor(model => model.actualBook.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.actualBook.Title)
@Html.ValidationMessageFor(model => model.actualBook.Title)
</div>
<div class="editor-label">
<label>Author@( Model.actualBook.Authors.Count > 1 ? "s" :"" )</label>
</div>
<div class="editor-field">
@Html.ListBox("AuthorIDs", Model.Authors)
@Html.ValidationMessageFor(model => model.actualBook.Authors)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.actualBook.Abstract)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.actualBook.Abstract)
@Html.ValidationMessageFor(model => model.actualBook.Abstract)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.actualBook.Year)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.actualBook.Year)
@Html.ValidationMessageFor(model => model.actualBook.Year)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.actualBook.GenreID, "Genre")
</div>
<div class="editor-field">
@Html.DropDownList("actualBook.GenreID", Model.Genres)
@Html.ValidationMessageFor(model => model.actualBook.GenreID)
</div>
这也适用于发布到控制器-Action
的ViewModel [HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(BookControllerViewModel bookVM)
{
if (ModelState.IsValid)
{
bookVM.actualBook.Authors = db.Authors.Where(x => bookVM.AuthorIDs.Contains(x.AuthorID)).ToList();
db.Entry(bookVM.actualBook).State = EntityState.Modified;
db.SaveChanges();
return Redirect(bookVM.redirectUrl);
}
bookVM.Authors = new MultiSelectList(db.Authors, "AuthorID", "Fullname", bookVM.actualBook.Authors.Select(x => x.AuthorID));
bookVM.Genres = new SelectList(db.Genres, "GenreID", "Name", bookVM.actualBook.GenreID);
return View(bookVM);
}
正确地填充了我期望的值。不起作用的是db.SaveChanges()似乎“默默地”拒绝保存我添加到书中的作者。 调试操作我可以看到bookVM.ActualBook.Authors实际上已正确设置并包含所选的Authors ...但是不会创建Jointable AuthorBooks的相应条目......
有人会知道为什么这不起作用,甚至可能是如何让它起作用?
提前致谢!
感谢 Gerts 答案,我通过将Controller-Action修改为
来实现此目的 [HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(BookControllerViewModel bookVM)
{
if (ModelState.IsValid)
{
var book = db.Books.Find(bookVM.actualBook.BookID);
book.Update(bookVM.actualBook);
book.Authors.Clear();
foreach(var aid in bookVM.AuthorIDs)
book.Authors.Add(db.Authors.Find(aid));
db.SaveChanges();
return Redirect(bookVM.redirectUrl);
}
bookVM.Authors = new MultiSelectList(db.Authors, "AuthorID", "Fullname", bookVM.actualBook.Authors.Select(x => x.AuthorID));
bookVM.Genres = new SelectList(db.Genres, "GenreID", "Name", bookVM.actualBook.GenreID);
return View(bookVM);
}
并向Book模型添加方法
internal void Update(Book book)
{
Title = book.Title;
Abstract = book.Abstract;
Year = book.Year;
GenreID = book.GenreID;
}
再次感谢格特!
答案 0 :(得分:2)
由于Book-Author是多对多关联,因此您必须首先加载actualBook.Authors
以便更改跟踪器能够注意到更改。然后,您可以添加/删除项目或将其替换为新的集合。不需要设置其状态。