blazor 项目无法调试_blazor服务器项目2

blazor 项目无法调试

CRUD (Create, Read, Update, Delete) are features that must be present in an application that uses a database. In the previous article, we discussed how to perform CRUD operations for a single table, Publisher table.

CRUD(创建,读取,更新,删除)是使用数据库的应用程序中必须具有的功能。 在上一篇文章中,我们讨论了如何对单个表Publisher表执行CRUD操作。

This article discusses how to create a CRUD operation involving the two tables, Book table and Publishertable, with the following N:1 (many-to-one) relationship.

本文讨论如何创建具有以下N:1(多对一)关系的涉及两个表Book表和Publisher表的CRUD操作。

CRUD页面概述 (Overview of the CRUD Pages)

Below is a page of the book list involving Book table and Publishertable. The first four columns are book attributes, and the fifth column is the publisher attribute.

以下是涉及Book表和Publisher表的书列表页面。 前四列是书籍属性,第五列是出版者属性。

Image for post
  • The list is sorted descending by Purchase Date. By clicking on the column title, Purchase Date, the order changes from descending to ascending. The same applies to other columns.

    该列表按购买日期降序排序。 通过单击列标题“ 购买日期” ,订单从降序更改为升序。 其他列也一样。

  • Navigation button:

    导航按钮:

    Navigation button: go to the previous page

    导航按钮: 转到上一页

    Navigation button: go to the previous page go to the next page

    导航按钮: 转到上一页转到下一页

    Navigation button: go to the previous page go to the next page1, 2, 3, ... page number

    导航按钮: 去前一页进入下一个页面123 ,...页码

  • To search books base on title criterium, type a title in the search box. The title does not have to complete.

    要根据标题标准搜索书籍,请在搜索框中输入标题。 标题不必填写。

  • To add new data, click Add new data

    要添加新数据,请单击Add new data

  • To change existing data, click Edit

    要更改现有数据,请单击“ Edit

  • To delete, click Delete

    要删除,请单击Delete

Below is a page to add a book involving Book table and Publishertable. All data input is book attributes. Pay attention to the last data input, Publisher. The last attribute of the book is input by selecting from the option list of publishers that are taken from the Publisher table.

下面是添加涉及Book表和Publisher表的书的页面。 所有数据输入均为书籍属性。 注意最后的数据输入Publisher 。 本书的最后一个属性是通过从Publisher表中获取的Publisher选项列表中进行选择来输入的。

Image for post

The following is a page to edit a book involving Book table and Publishertable. All data is book attributes. Pay attention to the last data, Publisher. The last attribute of the book is updated by selecting from the option list of publishers that are taken from the Publisher table.

以下是编辑涉及Book表和Publisher表的书的页面。 所有数据均为书籍属性。 注意最后一个数据Publisher 。 通过从Publisher表中选择发布者的选项列表,可以更新书籍的最后一个属性。

Image for post

Book: Add Data和创建存储过程 (Book Table: Add Data and Create Stored Procedures)

First of all, we need to write and execute SQL scripts for(1) adding data,(2) creating a stored procedure for adding new data, and(3) creating a stored procedure for updating data.

首先,我们需要编写和执行以下SQL脚本:(1)添加数据,(2)创建用于添加新数据的存储过程,以及(3)创建用于更新数据的存储过程。

  • Open SSMS.

    打开SSMS。
Image for post
  • Select the server name, click Connect

    选择服务器名称,单击“ Connect

Image for post
  • Open a new query editor by pressing Ctrl+N or selecting menu:

    通过按Ctrl+N或选择菜单来打开新的查询编辑器:

    Open a new query editor by pressing Ctrl+N or selecting menu:File| New|Query with Current Connection

    按打开一个新的查询编辑器Ctrl+N或选择菜单: File | New | Query with Current Connection

  • Copy the scripts, paste it into the query editor.

    复制脚本,将其粘贴到查询编辑器中。

USE [BookDB]
GOINSERT INTO dbo.Book(ISBN,PubYear,PurchDate,Title,PubId)VALUES ('9789791339957', 2013, '2019-10-01', 'Pranata Sosial', 6),
('9781292061184', 2015, '2018-02-12', 'Database Systems',9),
('9786024474348', 2019, '2020-08-17',
'Desain Basis Data Akademik Perguruan Tinggi', 11),
('9781305576766', 2015, '2018-12-31',
'NoSQL Web Development with Apache Cassandra', 10),
('9781484255087', 2019, '2019-10-01',
'Beginning Database Programming Using ASP.NET Core 3', 3),
('9781484231258', 2018, '2019-11-25',
'Expert Apache Cassandra Administration', 3),
('9781789619768', 2020, '2020-03-25',
'Modern Web Development with ASP.NET Core 3', 5),
('9781492056812', 2020, '2020-06-30',
'Programming C# 8.0', 7),
('9781783989201', 2015, '2020-07-23',
'Learning Apache Cassandra', 5),
('9781484259276', 2020, '2020-08-07',
'Microsoft Blazor: Building Web App in .NET', 3),
('9786020338682', 2017, '2020-08-10', 'Disruption', 2)
GOCREATE PROCEDURE [dbo].[spAddBook]@ISBN bigint,
@Title varchar(80),
@PubYear smallint,
@PurchDate date,
@PubId int
AS
BEGIN
INSERT INTO dbo.Book(ISBN,Title,PubYear,PurchDate,PubId)
VALUES (@ISBN, @Title, @PubYear, @PurchDate, @PubId)
SELECT @ISBN AS bookId;
END
GOCREATE PROCEDURE [dbo].[spUpdateBook]@ISBN bigint,
@Title varchar(80),
@PubYear smallint,
@PurchDate date,
@PubId int
AS
UPDATE Book
SET [Title] = @Title,
[PubYear] = @PubYear,
[PurchDate] = @PurchDate,
[PubId] = @PubId
WHERE [ISBN] = @ISBN
GO
  • Select menu: Query| Execute, or press F5 key to execute the script above.

    选择菜单: Query | Execute ,或按F5键执行上面的脚本。

支持CRUD操作的文件 (Files Supporting CRUD Operation)

Besides SQL script above, CRUD operation need files of entities, interfaces, implementation of interfaces, razor components, and code modification of some existing files.

除上面SQL脚本外,CRUD操作还需要实体,接口,接口的实现,剃刀组件以及一些现有文件的代码修改的文件。

实体文件 (Entity Files)

There are two entity files, Book.cs and BookPub.cs, placed in the Entities folder.

Entities文件夹中放置了两个实体文件Book.csBookPub.cs

Book.csThe Book.cs is a mapping of the Book table in the database.

Book.cs Book.cs是数据库中Book表的映射。

  • On the Solution Explorer window, right-click Entities, then click Add|Class

    在“ Solution Explorer窗口中,右键单击“ Entities ,然后单击“ Add |“确定”。 Class

  • Type Book.csas the file name, click Add.

    Book.cs作为文件名,单击Add

  • Click Book.cs to open the file, then copy and paste the following code.

    单击Book.cs打开文件,然后复制并粘贴以下代码。

using System;
using System.ComponentModel.DataAnnotations;namespace BookApp.Entities
{public class Book
{
[Key]
public long ISBN { get; set; }
public string Title { get; set; }
public short PubYear { get; set; }
public DateTime PurchDate { get; set; }
public int PubId { get; set; }
}
}

BookPub.csThe BookPub.cs is a mapping of the joining Book table and Publisher table. The BookPub.cs inherits properties from Book.cs. Copy and paste the following code.

BookPub.cs BookPub.cs联接Book表和Publisher表的映射。 BookPub.csBook.cs继承属性。 复制并粘贴以下代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;namespace BookApp.Entities
{ public class BookPub: Book
{
public string PubName { get; set; }
}
}

接口文件:IBookService.cs (Interface File: IBookService.cs)

  • IBookService.cs declares book methods, placed in the Interfaces folder.

    IBookService.cs声明放置在Interfaces文件夹中的书籍方法。

  • In the Interfaces folder, create the IBookService.cs file, then copy and paste the following code.

    在“ Interfaces文件夹中,创建IBookService.cs文件,然后复制并粘贴以下代码。

using BookApp.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;namespace BookApp.Interfaces
{public interface IBookService
{
Task<long> Create(Book book);
Task<int> Delete(long Id);
Task<int> Count(string search);
Task<int> Update(Book book);
Task<Book> GetById(long Id);
Task<List<BookPub>> ListAll(int skip, int take,
string orderBy, string direction, string search);
}
}

方法文件:BookService.cs (Method File: BookService.cs)

  • BookService.cs implements the methods declared in the IBookService.cs file, placed in the Data folder.

    BookService.cs实现了IBookService.cs文件中声明的方法,该文件位于Data文件夹中。

  • In the Data folder, create the BookService.cs file, then copy and paste the following code.

    在“ Data文件夹中,创建BookService.cs文件,然后复制并粘贴以下代码。

using BookApp.Interfaces;
using BookApp.Entities;
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;namespace BookApp.Data
{public class BookService : IBookService
{
private readonly IDapperService _dapperService; public BookService(IDapperService dapperService)
{
this._dapperService = dapperService;
} public Task<long> Create(Book book)
{
var dbPara = new DynamicParameters();
dbPara.Add("ISBN", book.ISBN, DbType.Int64);
dbPara.Add("Title", book.Title, DbType.String);
dbPara.Add("PubYear", book.PubYear, DbType.Int16);
dbPara.Add("PurchDate", book.PurchDate, DbType.Date);
dbPara.Add("PubId", book.PubId, DbType.Int32);
var bookId = Task.FromResult(_dapperService.Insert<long>
("[dbo].[spAddBook]",dbPara, commandType:
CommandType.StoredProcedure));
return bookId;
}public Task<Book> GetById(long id)
{
var book = Task.FromResult(_dapperService.Get<Book>
($"select * from [Book] where ISBN = {id}",
null,commandType: CommandType.Text));
return book;
} public Task<int> Delete(long id){
var deleteBook = Task.FromResult(_dapperService.
Execute($"Delete [Book] where ISBN = {id}",
null,commandType: CommandType.Text));
return deleteBook;
} public Task<int> Count(string search){
var totBook = Task.FromResult(_dapperService.Get<int>
($"select COUNT(*) from Book WHERE Title like
'%{search}%'",null,commandType: CommandType.Text));
return totBook;
} public Task<List<BookPub>> ListAll(int skip, int take,
string orderBy, string direction = "DESC",
string search = "")
{
var books = Task.FromResult(_dapperService.
GetAll<BookPub>($"SELECT b.*, p.Name PubName FROM
Book b LEFT OUTER JOIN Publisher p ON
b.PubId=p.Id WHERE Title like '%{search}%'
ORDER BY {orderBy} {direction} OFFSET {skip}
ROWS FETCH NEXT {take} ROWS ONLY;",null,
commandType: CommandType.Text));
return books;
} public Task<int> Update(Book book){
var dbPara = new DynamicParameters();
dbPara.Add("ISBN", book.ISBN, DbType.Int64);
dbPara.Add("Title", book.Title, DbType.String);
dbPara.Add("PubYear", book.PubYear, DbType.Int16);
dbPara.Add("PurchDate", book.PurchDate, DbType.Date);
dbPara.Add("PubId", book.PubId, DbType.Int32);
var updateBook = Task.FromResult(_dapperService.
Update<int>("[dbo].[spUpdateBook]",dbPara,
commandType:CommandType.StoredProcedure));
return updateBook;
}
}
}

组件文件*。 剃刀 (Component Files *. Razor)

There are three razor files added to the folder Page, that is AddBook.razor, EditBook.razor, and FetchBook.razor. All three contain code for I/O of the CRUD page.

文件Page添加了三个剃刀文件 ,分别是AddBook.razorEditBook.razorFetchBook.razor 。 所有这三个都包含CRUD页的I / O代码。

AddBook.razor

AddBook.razor

It’s used to create data for a new book.

它用于为新书创建数据。

@page "/addBook"
@inject IBookService bookService
@inject IPublisherService publisherService
@inject Microsoft.AspNetCore.Components.NavigationManager navigationManager<h3>
Add Book
</h3><form>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="ISBN" class="control-label">ISBN</label>
<input for="ISBN" class="form-control"
@bind="@book.ISBN" onfocus="this.value=''" />
</div>
<div class="form-group">
<label for="Title" class="control-label">Title</label>
<input for="Title" class="form-control"
@bind="@book.Title" />
</div>
<div class="form-group">
<label for="PubYear" class="control-label">
Publication Year</label>
<input for="PubYear" class="form-control"
@bind="@book.PubYear" onfocus="this.value=''" />
</div>
<div class="form-group">
<label for="PurchDate" class="control-label">
Purchase Date</label>
<input type="date" class="form-control"
@bind="@book.PurchDate" onfocus="this.value=''" />
</div>
<div class="form-group">
<label for="Publisher" class="control-label">
Publisher</label>
<select for="Publisher" class="form-control"
@bind="@book.PubId">
<option value=0 selected>[Select Publisher]</option>
@foreach (var publisher in publishers)
{
<option value="@publisher.Id">@publisher.Name</option>
}
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<button type="button" class="btn btn-primary"
@onclick="() => CreateBook()"> Save </button>
<button type="button" class="btn btn-warning"
@onclick="() => cancel()">Cancel</button>
</div>
</div>
</div>
</form>@code {
Book book = new Book();
List<Publisher> publishers = new List<Publisher>(); protected override async Task OnInitializedAsync(){
book.ISBN = 1234567890123;
book.PubYear = (short)DateTime.Now.Year;
book.PurchDate = DateTime.Now;
publishers = await publisherService.FetchAll();
} protected async Task CreateBook(){
await bookService.Create(book);
navigationManager.NavigateTo("/booklist");
} void cancel(){
navigationManager.NavigateTo("/booklist");
}
}

EditBook.razor

EditBook.razor

It’s used to update the data of a book.

用于更新书籍的数据。

@page "/editBook/{isbn:long}"
@inject IBookService bookService
@inject IPublisherService publisherService
@inject Microsoft.AspNetCore.Components.NavigationManager navigationManager<h3>
Edit Book
</h3><form>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="ISBN" class="control-label">ISBN</label>
<input for="ISBN" class="form-control"
@bind="@book.ISBN" />
</div>
<div class="form-group">
<label for="Title" class="control-label">Title</label>
<input for="Title" class="form-control"
@bind="@book.Title" />
</div>
<div class="form-group">
<label for="PubYear" class="control-label">
Publication Year</label>
<input for="PubYear" class="form-control"
@bind="@book.PubYear" />
</div>
<div class="form-group">
<label for="PurchDate" class="control-label">
Purchase Date</label>
<input type="date" class="form-control"
@bind="@book.PurchDate" />
</div>
<div class="form-group">
<label for="Publisher" class="control-label">
Publisher</label>
<select for="Publisher" class="form-control"
@bind="@book.PubId">
<option value=0 >[Select Publisher]</option>
@foreach (var publisher in publishers)
{
<option value="@publisher.Id">@publisher.Name</option>
}
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<button type="button" class="btn btn-primary"
@onclick="() => UpdateBook()"> Save </button>
<button type="button" class="btn btn-warning"
@onclick="() => cancel()">Cancel</button>
</div>
</div>
</div>
</form>@code {
[Parameter]public string isbn { get; set; } Book book = new Book();
List<Publisher> publishers = new List<Publisher>(); protected override async Task OnInitializedAsync(){
book = await bookService.GetById(isbn);
publishers = await publisherService.FetchAll();
} protected async Task UpdateBook(){
await bookService.Update(book);
navigationManager.NavigateTo("/booklist");
} void cancel()
{
navigationManager.NavigateTo("/booklist");
}
}

FetchBook.razor

FetchBook.razor

It’s used to display a list of books.

它用于显示书籍列表。

@page "/booklist"
@inject IBookService bookService<link href="https://stackpath.bootstrapcdn.com/font-awesome
/4.7.0/css/font-awesome.min.css" rel="stylesheet"><style>
.sort-th {
cursor: pointer;
} .fa {
float: right;
} .btn-custom {
color: black;
float: left;
padding: 8px 16px;
text-decoration: none;
transition: background-color .3s;
border: 2px solid #000;
margin: 0px 5px 0px 5px;
}
</style><div>
<a class="btn btn-primary" href='/addBook'>Add new data</a>
</div>@if (bookModel == null)
{
<p><em>Loading...</em></p>
}
else
{
<div class="row col-md-3 pull-right">
<input type="text" id="txtSearch"
placeholder="Search Names..." class="form-control"
@bind="SearchTerm" @bind:event="oninput" />
</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th class="sort-th"
@onclick="@(() => SortTable("ISBN"))">
I S B N
<span class="fa @(SetSortIcon("ISBN"))"></span>
</th>
<th class="sort-th"
@onclick="@(() => SortTable("Title"))">
T i t l e
<span class="fa @(SetSortIcon("Title"))"></span>
</th>
<th class="sort-th"
@onclick="@(() => SortTable("PubYear"))">
Pub.<br />Year
<span class="fa @(SetSortIcon("PubYear"))"></span>
</th>
<th class="sort-th"
@onclick="@(() => SortTable("PurchDate"))">
Purchase<br />Date
<span class="fa @(SetSortIcon("PurchDate"))"></span>
</th>
<th class="sort-th"
@onclick="@(() => SortTable("PubName"))">
Publisher
<span class="fa @(SetSortIcon("PubName"))"></span>
</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@if (bookModel == null || bookModel.Count == 0)
{
<tr>
<td colspan="3">
No Records to display
</td>
</tr>
}
else
{
foreach (var book in bookModel)
{
<tr>
<td>@book.ISBN</td>
<td>@book.Title</td>
<td>@book.PubYear</td>
<td>@book.PurchDate.ToShortDateString()</td>
<td>@book.PubName</td>
<td>
<a class="btn btn-primary"
href='/editBook/@book.ISBN'> Edit </a>
<a class="btn btn-warning"
@onclick="() => DeleteBook(book.ISBN)">
Delete </a>
</td>
</tr>
}
}
</tbody>
</table>
<div class="pagination">
<button class="btn btn-custom" @onclick=@(async ()=>
await NavigateToPage("previous"))>◀</button> @for (int i = startPage; i <= endPage; i++)
{
var currentPage = i;
<button class="btn btn-custom pagebutton
@(currentPage==curPage?"btn-info":"")"
@onclick=@(async () =>await refreshRecords
(currentPage))> @currentPage
</button>
} <button class="btn btn-custom" @onclick=
@(async ()=>await NavigateToPage("next"))>▶</button>
</div>
}@code {
private string searchTerm;
private string SearchTerm
{
get { return searchTerm; }
set { searchTerm = value; FilterRecords(); }
} List<BookPub> bookModel;
BookPub bookEntity = new BookPub(); #region Pagination int totalPages;
int totalRecords;
int curPage;
int pagerSize;
int pageSize;
int startPage;
int endPage;
string sortColumnName = "PurchDate";
string sortDir = "DESC"; #endregion protected override async Task OnInitializedAsync()
{
//display total page buttons
pagerSize = 3;
pageSize = 5;
curPage = 1;
bookModel = await bookService.ListAll((curPage - 1) *
pageSize, pageSize, sortColumnName, sortDir, searchTerm);
totalRecords = await bookService.Count(searchTerm);
totalPages =(int)Math.Ceiling(totalRecords/(decimal)pageSize);
SetPagerSize("forward");
} protected async Task DeleteBook(long id){
await bookService.Delete(id);
bookModel = await bookService.ListAll((curPage - 1) *
pageSize, pageSize, sortColumnName, sortDir, searchTerm);
} private bool isSortedAscending;
private string activeSortColumn; private async Task<List<BookPub>>
SortRecords(string columnName, string dir)
{
return await bookService.ListAll((curPage - 1) * pageSize,
pageSize, columnName, dir, searchTerm);
} private async Task SortTable(string columnName){
if (columnName != activeSortColumn)
{
bookModel = await SortRecords(columnName, "ASC");
isSortedAscending = true;
activeSortColumn = columnName;
}
else
{
if (isSortedAscending)
{
bookModel = await SortRecords(columnName, "DESC");
}
else
{
bookModel = await SortRecords(columnName, "ASC");
}
isSortedAscending = !isSortedAscending;
}
sortColumnName = columnName;
sortDir = isSortedAscending ? "ASC" : "DESC";
} private string SetSortIcon(string columnName){
if (activeSortColumn != columnName)
{
return string.Empty;
}
if (isSortedAscending)
{
return "fa-sort-up";
}
else
{
return "fa-sort-down";
}
} public async Task refreshRecords(int currentPage){
bookModel = await bookService.ListAll((currentPage - 1) *
pageSize, pageSize, sortColumnName, sortDir, searchTerm);
curPage = currentPage;
this.StateHasChanged();
} public void SetPagerSize(string direction){
if (direction == "forward" && endPage < totalPages)
{
startPage = endPage + 1;
if (endPage + pagerSize < totalPages)
{
endPage = startPage + pagerSize - 1;
}
else
{
endPage = totalPages;
}
this.StateHasChanged();
}
else if (direction == "back" && startPage > 1)
{
endPage = startPage - 1;
startPage = startPage - pagerSize;
}
else
{
startPage = 1;
endPage = totalPages;
}
} public async Task NavigateToPage(string direction){
if (direction == "next")
{
if (curPage < totalPages)
{
if (curPage == endPage)
{
SetPagerSize("forward");
}
curPage += 1;
}
}
else if (direction == "previous")
{
if (curPage > 1)
{
if (curPage == startPage)
{
SetPagerSize("back");
}
curPage -= 1;
}
}
await refreshRecords(curPage);
} public void FilterRecords(){
endPage = 0;
this.OnInitializedAsync().Wait();
}
}

代码修改 (Code Modification)

File NavMenu.razorModify the code so it becomes as follows.

文件NavMenu.razor修改代码,使其如下所示。

<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">Library</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div><div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="booklist">
<span class="oi oi-book"
aria-hidden="true"></span> Books
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="publisherlist">
<span class="oi oi-list-rich"
aria-hidden="true"></span> Publishers
</NavLink>
</li>
</ul>
</div>@code {
private bool collapseNavMenu = true; private string NavMenuCssClass => collapseNavMenu ?
"collapse" : null; private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}

Startup.csAdd the following service.

Startup.cs添加以下服务

//Book service
services.AddScoped<IBookService, BookService>();

The following is the overall project structure.

以下是总体项目结构。

Image for post

翻译自: https://medium.com/informatics/blazor-server-project-2-6e49418c4d18

blazor 项目无法调试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值