【发布时间】:2017-10-13 14:46:21
【问题描述】:
我正在尝试显示一个书籍列表,其中将显示每本书的详细信息。除了与 Books 模型具有多对多关系的属性外,它都可以正常工作。
这是我的 Book 模型(为了便于阅读,我删除了注释):
public class Book
{
public int BookId { get; set; }
public string title { get; set; }
public Int32 isbn { get; set; }
public string author { get; set; }
public string summary { get; set; }
public string series { get; set; }
public string amazonLink { get; set; }
public string pubLink { get; set; }
public int? GradeLevelId { get; set; } //Foreign Key for GradeLevel
public bool needsEdit { get; set; }
public int? LexileLevelId { get; set; } //Foreign Key for LexileLevel
public DateTime dateAdded { get; set; }
public Book()
{
dateAdded = DateTime.Now;
}
public string comments { get; set; }
public virtual GradeLevel GradeLevel { get; set; }
public virtual LexileLevel LexileLevel { get; set; }
//Navigation Properties
public virtual ICollection<Recommendation> Recommendations { get; set; }
public virtual ICollection<RelevantGenre> RelevantGenres { get; set; }
}
两个导航属性(Recommendation 和 RelevantGenre)用于关联/连接表,这就是我遇到问题的地方。为简单起见,我将专注于 RelevantGenre 模型。每本书可以有多个类型,因此 RelevantGenre 是 Book 和 Genre 之间的连接表。
这是适合这些人的模型:
public class RelevantGenre
{
//Both are primary keys
[Key]
[Column(Order = 1)]
public int BookId { get; set; } //Foreign Key to Book
[Key]
[Column(Order = 2)]
public int genreId { get; set; } //Foreign Key to Genre
public virtual Book Book { get; set; } //Nav property
public virtual Genre Genre { get; set; } //Nav property
}
public class Genre
{
public int GenreId { get; set; }
public string genreTitle { get; set; }
public int genreOrder { get; set; }
//Navigation Property to RelevantGenre
public ICollection<RelevantGenre> RelevantGenres { get; set; }
}
这是控制器:
// GET: Books
public ActionResult Index(string filter, string searchString)
{
var viewModel = new BookListViewModel();
if (String.IsNullOrEmpty(searchString) && String.IsNullOrEmpty(filter))
{
var results = from b in db.Books select b;
var resultsList = (results.ToList());
viewModel.Books = resultsList;
return View(viewModel);
}
else
{
var results = from b in db.Books select b;
//Filtering the book list
switch (filter)
{
case "HR":
results = from b in db.Books
join r in db.Recommendations
on new { b.BookId } equals
new { r.BookId }
where (r.RecommendationTypeId == 1)
select b;
break;
default:
results = from b in db.Books select b;
break;
}
if(!String.IsNullOrEmpty(searchString))
{
//Search query results
var searchResults = from b in db.Books
.Where(model => model.title.Contains(searchString) || model.author.Contains(searchString)
|| model.series.Contains(searchString))
select b;
if (searchResults != null )
{
results = searchResults;
}
else
{
ViewBag.SpanText = "Sorry, no results founds. Please try your search again.";
}
}
var resultsList = (results.ToList());
viewModel.Books = resultsList;
return View(viewModel);
}
}
如您所见,它返回了一个 viewModel,因为我认为这对于如何返回模型数据的组合最有意义。
这是视图模型:
public class BookListViewModel
{
public List<Book> Books { get; set; }
public int BookId { get; set; }
public string title { get; set; }
public string author { get; set; }
public Int32 isbn { get; set; }
public string series { get; set; }
public int? GradeLevelId { get; set; }
public string gradeLevelName { get; set; }
public int? LexileLevelId { get; set; }
public string lexileLevelName { get; set; }
public Recommendation Recommendation { get; set; }
public int RecommendationTypeId { get; set; }
public string recName { get; set; }
public RelevantGenre RelevantGenre { get; set; }
public int genreId { get; set; }
}
最后,这是视图:
@model FavBooks.ViewModels.BookListViewModel
@{
ViewBag.Title = "All Books";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Books</h2>
<p class="details">
@Html.ActionLink("Browse All Books in List Format", "FullList", "Books")
</p>
@foreach (var item in Model.Books)
{
<div class="row fullBorder">
<div class="col-md-2 col-sm-2">
<img src="~/Content/Images/harrypotterbook.png" class="bookThumb" alt="Book Image" />
</div>
<div class="col-md-3 col-xs-3">
<h3>
<a href="@Url.Action("Details", "Books", new { id = item.BookId })" class="darkLink bookTitle">
@Html.DisplayFor(modelItem => item.title)
</a>
</h3>
<h4>By @Html.DisplayFor(modelItem => item.author)</h4>
<p><strong>ISBN:</strong> @Html.DisplayFor(modelItem => item.isbn)</p>
</div>
<div class="col-md-3 col-sm-4 bookMargins">
@{
if (item.series != null)
{
<p><strong>Series:</strong> @Html.DisplayFor(modelItem => item.series) </p>
}
else
{
<p></p>
}
}
<p><strong>Grade Level:</strong> @Html.DisplayFor(modelItem => item.GradeLevel.gradeLevelName )</p>
<p><strong>Lexile Level:</strong> @Html.DisplayFor(modelItem => item.LexileLevel.lexileLevelName)</p>
</div>
<div class="col-md-4 col-sm-3">
@Html.ActionLink("View Book Details", "Details", "Books", new { id = item.BookId }, new { @class="btn btn-default btnBookDetails" })
</div>
</div>
}
您可以看到,我的视图使用 foreach 循环显示了 Model.Books 中的项目列表。对于每本书,我希望它还显示与该书相关的 RelevantGenres,但它不允许我这样做。 GradeLevel 和 LexileLevel 属性连接得很好(它们是一对多的),但它似乎没有注册任何不直接属于 Book 模型的多对多关系。
我觉得我在这里缺少一些基本的东西,或者我的视图模型设置有问题。您是否看到我在这方面出了什么问题,或者我可以做些什么来显示每本书的流派?
编辑:
让我更具体地说明我的尝试。
我看到here 可以在另一个 foreach 中使用一个 foreach 来显示一个循环。但是当我尝试这样做时,它告诉我“foreach 无法对其进行操作......因为 Favbooks.Models.Book 不包含 GetEnumerator 的公共定义”。所以我尝试将@model 更改为 IEnumerable 并循环遍历整个模型( 而不是 foreach(var item in Model.Books) 但它仍然无法正常工作。在那种情况下,它给了我一个错误说:
“BookListViewModel”不包含“RelevantGenres”的定义,并且找不到接受“BookListViewModel”类型的第一个参数的扩展方法“RelevantGenres”(您是否缺少 using 指令或程序集引用?)
因为这不起作用,我将@model 保留为@model FavBooks.ViewModels.BookListViewModel,就像最初一样,并尝试输入@Html.DisplayFor(modelItem => item.Genres.genreTitle),但它无法识别流派或相关流派。
总而言之, 问题在于,如果我遍历 Model.Books,则它不会识别视图模型中除 Books 列表之外的任何内容。但是如果我遍历整个模型,那么它仍然无法识别 RelevantGenres,现在它开始给我另一个类似这样的错误:
传入字典的模型项的类型为“FavBooks.ViewModels.BookListViewModel”,但此字典需要类型为“System.Collections.Generic.IEnumerable`1[FavBooks.ViewModels.BookListViewModel]”的模型项。
如果这不是完全清楚,我很抱歉。我以前没有用过太多的视图模型,我发现我一定是设置错了,但我只是不知道如何让它工作......
【问题讨论】:
-
有什么问题?
-
好吧,首先,您实际上并没有在视图中显示流派。你的意思是 RelevantGenre 是空的吗?那是因为你实际上并没有在任何地方设置它。如果您的意思是如果您浏览书籍的导航,那么很难知道,因为您没有显示任何实际尝试过的代码。仅供参考,书籍/类型没有多对多,它是一对多。
-
我刚刚在问题中添加了更多细节,希望对您有所帮助。 @ErikFunkenbusch 你能解释一下我实际上没有设置 RelevantGenre 的意思吗?而且,我的设置有点不寻常,因为每本书都可以有多个流派,并且每个流派都应该能够提取具有该流派的书籍列表。那么在这种情况下,1 比多如何呢?
-
@Sh306 - 出于某种原因,您正在创建一个名为 ReleventGenre 的联结类,它实际上应该称为 BookGenre 或 GenreBook,以便让框架自动将其识别为联结表。事实上,您甚至不需要这个类,因为 EF 会自动使用名为 BookGenre 或 GenreBook 的表。您可以使用以下地图覆盖它:entityframeworktutorial.net/code-first/…,然后您将删除 ReleventGenres 类并让 Book 和 Genre 包含两者的集合。
-
如果您打算拥有一个带有有效负载的联结表(除了联接之外的其他数据),您只需要 ReleventGenre 表
标签: c# asp.net-mvc entity-framework viewmodel navigation-properties