Home > Article > Backend Development > Elasticsearch.Net usage tutorial MVC4 book management system (2)
The example in this article shares the tutorial for making the MVC4 book management system for your reference. The specific content is as follows
First of all, the project structure diagram:
The relevant code of the Model layer is as follows:
Book.cs code is as follows:
public class Book { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } [MaxLength(500)] [Display(Name = "标题")] public string Title { get; set; } [MaxLength(5000)] [Display(Name = "前言")] public string Foreword { get; set; } [Display(Name = "总页数")] public int Pages { get; set; } [Display(Name = "作者")] public string Author { get; set; } }
public class AppContext:DbContext { public AppContext() { } public DbSet<Book> Books { get; set; } }
ViewModels related:
public class SearchViewModel { public string Query { get; set; } public IEnumerable<IHit<Book>> Results { get; set; } public IDictionary<string, Suggest[]> Suggestions { get; set; } public long Elapsed { get; set; } }
The next step is the code of HomeController.cs and BooksController.cs:
public class HomeController : Controller { private SearchService _searchService; public HomeController() { _searchService = new SearchService(); } public ActionResult Index() { return View(); } public ActionResult Search(string query, int page = 0, int pageSize = 10) { var result = _searchService.Find(query, page, pageSize); var suggestion = _searchService.FindPhraseSuggestion(query, 0, 3); var viewModel = new SearchViewModel { Query = query, Results = result.Item1,Elapsed = result.Item2, Suggestions = suggestion }; return View("Index", viewModel); } }
public class BooksController : Controller { private AppContext db = new AppContext(); public ActionResult Index() { return View(db.Books.ToList()); } public ActionResult Details(Guid? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Book book = db.Books.Find(id); if (book == null) { return HttpNotFound(); } return View(book); } public ActionResult Create() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include="Id,Title,Foreword,Pages,Author")] Book book) { if (ModelState.IsValid) { book.Id = Guid.NewGuid(); db.Books.Add(book); db.SaveChanges(); //添加书 Elasticsearch.Elasticsearch.Client.Index<Book>(book); return RedirectToAction("Index"); } return View(book); } public ActionResult Edit(Guid? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Book book = db.Books.Find(id); if (book == null) { return HttpNotFound(); } return View(book); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include="Id,Title,Foreword,Pages,Author")] Book book) { if (ModelState.IsValid) { db.Entry(book).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(book); } public ActionResult Delete(Guid? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Book book = db.Books.Find(id); if (book == null) { return HttpNotFound(); } return View(book); } [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(Guid id) { Book book = db.Books.Find(id); db.Books.Remove(book); db.SaveChanges(); return RedirectToAction("Index"); } public JsonResult Reindex() { foreach (var book in db.Books) { //Indexing book Elasticsearch.Elasticsearch.Client.Index<Book>(book); } return Json("OK",JsonRequestBehavior.AllowGet); } protected override void Dispose(bool disposing) { if (disposing) { db.Dispose(); } base.Dispose(disposing); } }
Elasticsearch auxiliary class:
First is the Elasticsearch.cs
public class Elasticsearch { private static ElasticClient _client; public static ElasticClient Client { get { if (_client == null) { //连接配置 var setting = new ConnectionSettings(ElasticsearchConfiguration.Connection,ElasticsearchConfiguration.DefaultIndex); _client = new ElasticClient(setting); } return _client; } } }
ElasticsearchConfiguration.cs class
public static class ElasticsearchConfiguration { public static string Host { get { return "http://localhost"; } } public static long Port { get { return 9200; } } public static Uri Connection { get { return new Uri(string.Format("{0}:{1}", Host, Port)); } } public static string DefaultIndex { get { return "library"; } } }
SearchService.cs code:
public class SearchService { public double MinScore { get {return 0.0005; }} //高亮标记前缀 public string PreHighlightTag { get { return @"<strong>"; } } //高亮标记后缀 public string PostHighlightTag { get { return @"</strong>"; } } public Tuple< IEnumerable<IHit<Book>>,long> Find(string query, int page = 0, int pageSize = 10) { var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s .From(page * pageSize) .Size(pageSize) .MinScore(MinScore) .Highlight(h => h .PreTags(PreHighlightTag) .PostTags(PostHighlightTag) .OnFields( f => f.OnField(b => b.Foreword), f => f.OnField(b => b.Title) )) .Query(q => q.QueryString(qs => qs.Query(query).UseDisMax()))); return new Tuple<IEnumerable<IHit<Book>>, long>(result.Hits,result.ElapsedMilliseconds); } //查找短语建议 public IDictionary<string, Suggest[]> FindPhraseSuggestion(string phrase, int page = 0, int pageSize = 5) { var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s .From(page*pageSize) .Size(pageSize) .SuggestPhrase("did-you-mean", ps => ps .Text(phrase) .OnField(f => f.Foreword)) .Query(q => q.MatchAll())); return result.Suggest; } public IEnumerable<IHit<Book>> FindAll() { var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s.AllIndices()); return result.Hits; } }
Views view
Books folder:
Index.cshtml:
@model IEnumerable<Library.Web.Models.Book> @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Index</h2> <p> @Html.ActionLink("创建新书", "Create") </p> <table class="table"> <tr> <th> @Html.DisplayNameFor(model => model.Title) </th> <th> @Html.DisplayNameFor(model => model.Foreword) </th> <th> @Html.DisplayNameFor(model => model.Pages) </th> <th> @Html.DisplayNameFor(model => model.Author) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Title) </td> <td> @Html.DisplayFor(modelItem => item.Foreword) </td> <td> @Html.DisplayFor(modelItem => item.Pages) </td> <td> @Html.DisplayFor(modelItem => item.Author) </td> <td> @Html.ActionLink("编辑", "Edit", new { id=item.Id }) | @Html.ActionLink("详细", "Details", new { id=item.Id }) | @Html.ActionLink("删除", "Delete", new { id=item.Id }) </td> </tr> } </table>
Edit.cshtml:
@model Library.Web.Models.Book @{ ViewBag.Title = "Edit"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Book</h4> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.Id) <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Foreword, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.TextAreaFor(model => model.Foreword) @Html.ValidationMessageFor(model => model.Foreword) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Pages, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Pages) @Html.ValidationMessageFor(model => model.Pages) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Author, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Author) @Html.ValidationMessageFor(model => model.Author) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("返回列表", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Details.cshtml:
@model Library.Web.Models.Book @{ ViewBag.Title = "Details"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Details</h2> <div> <h4>Book</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Title) </dt> <dd> @Html.DisplayFor(model => model.Title) </dd> <dt> @Html.DisplayNameFor(model => model.Foreword) </dt> <dd> @Html.DisplayFor(model => model.Foreword) </dd> <dt> @Html.DisplayNameFor(model => model.Pages) </dt> <dd> @Html.DisplayFor(model => model.Pages) </dd> <dt> @Html.DisplayNameFor(model => model.Author) </dt> <dd> @Html.DisplayFor(model => model.Author) </dd> </dl> </div> <p> @Html.ActionLink("编辑", "Edit", new { id = Model.Id }) | @Html.ActionLink("返回列表", "Index") </p>
Delete.cshtml:
@model Library.Web.Models.Book @{ ViewBag.Title = "Delete"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> <div> <h4>Book</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Title) </dt> <dd> @Html.DisplayFor(model => model.Title) </dd> <dt> @Html.DisplayNameFor(model => model.Foreword) </dt> <dd> @Html.DisplayFor(model => model.Foreword) </dd> <dt> @Html.DisplayNameFor(model => model.Pages) </dt> <dd> @Html.DisplayFor(model => model.Pages) </dd> <dt> @Html.DisplayNameFor(model => model.Author) </dt> <dd> @Html.DisplayFor(model => model.Author) </dd> </dl> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-actions no-color"> <input type="submit" value="Delete" class="btn btn-default" /> | @Html.ActionLink("返回列表", "Index") </div> } </div>
Create.cshtml:
@model Library.Web.Models.Book @{ ViewBag.Title = "Create"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>创建</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Book</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Foreword, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.TextAreaFor(model => model.Foreword) @Html.ValidationMessageFor(model => model.Foreword) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Pages, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Pages) @Html.ValidationMessageFor(model => model.Pages) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Author, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Author) @Html.ValidationMessageFor(model => model.Author) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="创建" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("回到列表", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Home-& gt; Index.cshtml
@model Library.Web.ViewModels.SearchViewModel @{ ViewBag.Title = "Elasticsearch"; } <div class="jumbotron"> <h1>Elasticsearch入门</h1> <p class="lead">安装和配置群集</p> <ol> <li> <a href="http://www.oracle.com/technetwork/java/ javase/downloads/index.html">安装Java</a> </li> <li> <a href="http://www.elasticsearch.org/ download/">安装Elasticsearch</a> </li> <li>运行Elasticsearch</li> <li><a href="/Books/Create">增加一些书籍</a></li> </ol> </div> @if (Model == null) { return; } <div style="margin-top: 30px;"> @if (Model.Suggestions.Any(x => x.Key == "did-you-mean")) { <span>你的意思是: </span> foreach (var suggestions in Model.Suggestions["did-you-mean"]) { var count = 0; foreach (var suggestion in suggestions.Options) { <a href="/Home/Search?query=@suggestion.Text"><strong>@suggestion.Text </strong> </a> count++; } if (count == 0) { <span class="alert-danger">没有建议!</span> } } } </div> <h3><strong>Results for:</strong> @Model.Query</h3> @if (Model != null) { <table class="table table-condensed"> <thead> <tr><th>文档的分数(排名相关度)</th><th>Title</th><th>Content</th><th>Author</th></tr> </thead> <tbody> @foreach (var result in Model.Results) { <tr> <td>@result.Score</td> <td> <a href="/Books/Details/@result.Id"> @if (result.Highlights != null && result.Highlights.Any(x => x.Key == "title")) { var hl = result.Highlights.FirstOrDefault(x => x.Key == "title"); foreach (var h in hl.Value.Highlights) { WriteLiteral(h); } } else { WriteLiteral(result.Source.Title); } </a> </td> <td> @if (result.Highlights != null && result.Highlights.Any(x => x.Key == "foreword")) { var hl = result.Highlights.FirstOrDefault(x => x.Key == "foreword"); foreach (var h in hl.Value.Highlights) { WriteLiteral(h + "..."); } } </td> <td>@result.Source.Author</td> </tr> } @if (!Model.Results.Any()) { <tr> <td colspan="4" class="alert alert-danger" style="text-align:center;">没有结果发现:(</td> </tr> } </tbody> </table> <h4><span class="label label-default">@Model.Results.Count()</span>搜索结果用了 @Model.Elapsed 毫秒</h4> }
_Layout.cshtml
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> @Html.ActionLink("Elasticsearch MVC示例", "Index", "Home", null, new { @class = "navbar-brand" }) </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("Books", "Index", "Books")</li> </ul> @using (Html.BeginForm("Search", "Home", FormMethod.Get,new {@class = "navbar-form navbar-left"})) { <div class="form-group"> <input class="form-control" type="text" placeholder="搜索" name="query" /> </div> <button type="submit" class="btn btn-default">提交</button> } </div> </div> </div> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>© @DateTime.Now.Year - Elasticsearch, Nest, ASP.NET 应用</p> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html>
The result is as shown in the picture:
List page
Creation page:
The above is the entire content of this article, I hope it will be helpful to everyone’s learning. Help, and I hope everyone will support the PHP Chinese website.