Browse Source

SP_12062024_AuthorUserInterFace

main
Soumen Pal 7 months ago
parent
commit
a179a764d7
26 changed files with 3027 additions and 224 deletions
  1. +1
    -0
      angular/src/app/app-routing.module.ts
  2. +11
    -0
      angular/src/app/author/author-routing.module.ts
  3. +99
    -0
      angular/src/app/author/author.component.html
  4. +0
    -0
      angular/src/app/author/author.component.scss
  5. +23
    -0
      angular/src/app/author/author.component.spec.ts
  6. +93
    -0
      angular/src/app/author/author.component.ts
  7. +21
    -0
      angular/src/app/author/author.module.ts
  8. +16
    -0
      angular/src/app/book/book.component.html
  9. +59
    -51
      angular/src/app/book/book.component.ts
  10. +10
    -2
      angular/src/app/proxy/books/book.service.ts
  11. +8
    -1
      angular/src/app/proxy/books/models.ts
  12. +182
    -102
      angular/src/app/proxy/generate-proxy.json
  13. +14
    -16
      angular/src/app/route.provider.ts
  14. +12
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/AuthorLookupDto.cs
  15. +4
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/BookDto.cs
  16. +3
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/CreateUpdateBookDto.cs
  17. +2
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/IBookAppService.cs
  18. +1
    -0
      aspnet-core/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
  19. +116
    -24
      aspnet-core/src/Acme.BookStore.Application/Books/BookAppService.cs
  20. +8
    -1
      aspnet-core/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
  21. +55
    -27
      aspnet-core/src/Acme.BookStore.Domain/BookStoreDataSeederContributor.cs
  22. +2
    -0
      aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs
  23. +2
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs
  24. +2220
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240612062933_Added_AuthorId_To_Book.Designer.cs
  25. +51
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240612062933_Added_AuthorId_To_Book.cs
  26. +14
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs

+ 1
- 0
angular/src/app/app-routing.module.ts View File

@ -28,6 +28,7 @@ const routes: Routes = [
{ path: 'books', loadChildren: () => import('./book/book.module').then(m => m.BookModule) }, { path: 'books', loadChildren: () => import('./book/book.module').then(m => m.BookModule) },
{ path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) }, { path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
{ path: 'book-issue', loadChildren: () => import('./book-issue/book-issue.module').then(m => m.BookIssueModule) }, { path: 'book-issue', loadChildren: () => import('./book-issue/book-issue.module').then(m => m.BookIssueModule) },
{ path: 'authors', loadChildren: () => import('./author/author.module').then(m => m.AuthorModule) },
]; ];
@NgModule({ @NgModule({


+ 11
- 0
angular/src/app/author/author-routing.module.ts View File

@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthorComponent } from './author.component';
const routes: Routes = [{ path: '', component: AuthorComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AuthorRoutingModule { }

+ 99
- 0
angular/src/app/author/author.component.html View File

@ -0,0 +1,99 @@
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ '::Menu:Authors' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6">
<div class="text-lg-end pt-2">
<button *abpPermission="'BookStore.Authors.Create'" id="create" class="btn btn-primary" type="button" (click)="createAuthor()">
<i class="fa fa-plus me-1"></i>
<span>{{ '::NewAuthor' | abpLocalization }}</span>
</button>
</div>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="author.items" [count]="author.totalCount" [list]="list" default>
<ngx-datatable-column
[name]="'::Actions' | abpLocalization"
[maxWidth]="150"
[sortable]="false"
>
<ng-template let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button *abpPermission="'BookStore.Authors.Edit'" ngbDropdownItem (click)="editAuthor(row.id)">
{{ '::Edit' | abpLocalization }}
</button>
<button *abpPermission="'BookStore.Authors.Delete'" ngbDropdownItem (click)="delete(row.id)">
{{ '::Delete' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
<ngx-datatable-column [name]="'::BirthDate' | abpLocalization">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.birthDate | date }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ (selectedAuthor.id ? '::Edit' : '::NewAuthor') | abpLocalization }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="form-group">
<label for="author-name">Name</label><span> * </span>
<input type="text" id="author-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="mt-2">
<label>Birth date</label><span> * </span>
<input
#datepicker="ngbDatepicker"
class="form-control"
name="datepicker"
formControlName="birthDate"
ngbDatepicker
(click)="datepicker.toggle()"
/>
</div>
<div class="form-group">
<label for="short-bio">Short Bio</label><span> * </span>
<input type="text" id="short-bio" class="form-control" formControlName="shortBio" />
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>
{{ '::Close' | abpLocalization }}
</button>
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
<i class="fa fa-check mr-1"></i>
{{ '::Save' | abpLocalization }}
</button>
</ng-template>
</abp-modal>

+ 0
- 0
angular/src/app/author/author.component.scss View File


+ 23
- 0
angular/src/app/author/author.component.spec.ts View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AuthorComponent } from './author.component';
describe('AuthorComponent', () => {
let component: AuthorComponent;
let fixture: ComponentFixture<AuthorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AuthorComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AuthorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 93
- 0
angular/src/app/author/author.component.ts View File

@ -0,0 +1,93 @@
import { Component, OnInit } from '@angular/core';
import { ListService, PagedResultDto } from '@abp/ng.core';
import { AuthorService, AuthorDto } from '@proxy/authors';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
@Component({
selector: 'app-author',
templateUrl: './author.component.html',
styleUrls: ['./author.component.scss'],
providers: [ListService, { provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
})
export class AuthorComponent implements OnInit {
author = { items: [], totalCount: 0 } as PagedResultDto<AuthorDto>;
isModalOpen = false;
form: FormGroup;
selectedAuthor = {} as AuthorDto;
constructor(
public readonly list: ListService,
private authorService: AuthorService,
private fb: FormBuilder,
private confirmation: ConfirmationService
) {}
ngOnInit(): void {
const authorStreamCreator = (query) => this.authorService.getList(query);
this.list.hookToQuery(authorStreamCreator).subscribe((response) => {
this.author = response;
});
}
createAuthor() {
this.selectedAuthor = {} as AuthorDto;
this.buildForm();
this.isModalOpen = true;
}
editAuthor(id: string) {
this.authorService.get(id).subscribe((author) => {
this.selectedAuthor = author;
this.buildForm();
this.isModalOpen = true;
});
}
buildForm() {
this.form = this.fb.group({
name: [this.selectedAuthor.name || '', Validators.required],
birthDate: [
this.selectedAuthor.birthDate ? new Date(this.selectedAuthor.birthDate) : null,
Validators.required,
],
shortBio:[this.selectedAuthor.shortBio || '', Validators.required],
});
}
save() {
if (this.form.invalid) {
return;
}
if (this.selectedAuthor.id) {
this.authorService
.update(this.selectedAuthor.id, this.form.value)
.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
} else {
this.authorService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
}
delete(id: string) {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure')
.subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.authorService.delete(id).subscribe(() => this.list.get());
}
});
}
}

+ 21
- 0
angular/src/app/author/author.module.ts View File

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthorRoutingModule } from './author-routing.module';
import { AuthorComponent } from './author.component';
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap';
import { SharedModule } from '../shared/shared.module';
@NgModule({
declarations: [
AuthorComponent
],
imports: [
CommonModule,
AuthorRoutingModule,
NgbDatepickerModule,
SharedModule
]
})
export class AuthorModule { }

+ 16
- 0
angular/src/app/book/book.component.html View File

@ -63,6 +63,12 @@
{{ row.price | currency }} {{ row.price | currency }}
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column
[name]="'::Author' | abpLocalization"
prop="authorName"
[sortable]="false"
></ngx-datatable-column>
</ngx-datatable> </ngx-datatable>
</div> </div>
</div> </div>
@ -104,6 +110,16 @@
(click)="datepicker.toggle()" (click)="datepicker.toggle()"
/> />
</div> </div>
<div class="form-group">
<label for="author-id">Author</label><span> * </span>
<select class="form-control" id="author-id" formControlName="authorId">
<option [ngValue]="null">Select author</option>
<option [ngValue]="author.id" *ngFor="let author of authors$ | async">
{{ author.name }}
</option>
</select>
</div>
</form> </form>
</ng-template> </ng-template>


+ 59
- 51
angular/src/app/book/book.component.ts View File

@ -1,32 +1,41 @@
import { ListService, PagedResultDto } from '@abp/ng.core'; import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { BookService, BookDto, bookTypeOptions, AuthorLookupDto } from '@proxy/books';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-book', selector: 'app-book',
templateUrl: './book.component.html', templateUrl: './book.component.html',
styleUrls: ['./book.component.scss'], styleUrls: ['./book.component.scss'],
providers: [ListService,
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line
],
providers: [ListService, { provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
}) })
export class BookComponent implements OnInit { export class BookComponent implements OnInit {
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>;
selectedBook = {} as BookDto; // declare selectedBook
isModalOpen = false; // add this line
form: FormGroup; // add this line
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>;
form: FormGroup;
selectedBook = {} as BookDto;
authors$: Observable<AuthorLookupDto[]>;
bookTypes = bookTypeOptions; bookTypes = bookTypeOptions;
constructor(public readonly list: ListService, private bookService: BookService, private fb: FormBuilder,
private confirmation: ConfirmationService
) {}
isModalOpen = false;
constructor(
public readonly list: ListService,
private bookService: BookService,
private fb: FormBuilder,
private confirmation: ConfirmationService
) {
this.authors$ = bookService.getAuthorLookup().pipe(map((r) => r.items));
}
ngOnInit() { ngOnInit() {
debugger;
const bookStreamCreator = (query) => this.bookService.getList(query); const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => { this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
@ -34,55 +43,54 @@ export class BookComponent implements OnInit {
}); });
} }
// add new method
createBook() { createBook() {
this.buildForm(); // add this line
this.selectedBook = {} as BookDto; // reset the selected book
this.selectedBook = {} as BookDto;
this.buildForm();
this.isModalOpen = true; this.isModalOpen = true;
} }
editBook(id: string) {
this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
this.buildForm();
this.isModalOpen = true;
});
}
buildForm() { buildForm() {
this.form = this.fb.group({ this.form = this.fb.group({
name: ['', Validators.required],
type: [null, Validators.required],
publishDate: [null, Validators.required],
price: [null, Validators.required],
authorId: [this.selectedBook.authorId || null, Validators.required],
name: [this.selectedBook.name || null, Validators.required],
type: [this.selectedBook.type || null, Validators.required],
publishDate: [
this.selectedBook.publishDate ? new Date(this.selectedBook.publishDate) : null,
Validators.required,
],
price: [this.selectedBook.price || null, Validators.required],
}); });
} }
save() { save() {
if (this.form.invalid) { if (this.form.invalid) {
return; return;
} }
const request = this.selectedBook.id const request = this.selectedBook.id
? this.bookService.update(this.selectedBook.id, this.form.value)
: this.bookService.create(this.form.value);
request.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
? this.bookService.update(this.selectedBook.id, this.form.value)
: this.bookService.create(this.form.value);
// Add editBook method
editBook(id: string) {
this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
this.buildForm();
this.form.controls["name"].setValue(this.selectedBook.name);
this.form.controls["type"].setValue(this.selectedBook.type);
this.form.controls["publishDate"].setValue(this.selectedBook.publishDate);
this.form.controls["price"].setValue(this.selectedBook.price);
this.isModalOpen = true;
});
}
request.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
delete(id: string) {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
delete(id: string) {
this.confirmation.warn('::AreYouSureToDelete', 'AbpAccount::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
} }

+ 10
- 2
angular/src/app/proxy/books/book.service.ts View File

@ -1,6 +1,6 @@
import type { BookDto, CreateUpdateBookDto } from './models';
import type { AuthorLookupDto, BookDto, CreateUpdateBookDto } from './models';
import { RestService, Rest } from '@abp/ng.core'; import { RestService, Rest } from '@abp/ng.core';
import type { PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
import type { ListResultDto, PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
@Injectable({ @Injectable({
@ -35,6 +35,14 @@ export class BookService {
{ apiName: this.apiName,...config }); { apiName: this.apiName,...config });
getAuthorLookup = (config?: Partial<Rest.Config>) =>
this.restService.request<any, ListResultDto<AuthorLookupDto>>({
method: 'GET',
url: '/api/app/book/author-lookup',
},
{ apiName: this.apiName,...config });
getBookDropDown = (config?: Partial<Rest.Config>) => getBookDropDown = (config?: Partial<Rest.Config>) =>
this.restService.request<any, BookDto[]>({ this.restService.request<any, BookDto[]>({
method: 'GET', method: 'GET',


+ 8
- 1
angular/src/app/proxy/books/models.ts View File

@ -1,11 +1,17 @@
import type { AuditedEntityDto } from '@abp/ng.core';
import type { AuditedEntityDto, EntityDto } from '@abp/ng.core';
import type { BookType } from './book-type.enum'; import type { BookType } from './book-type.enum';
export interface AuthorLookupDto extends EntityDto<string> {
name?: string;
}
export interface BookDto extends AuditedEntityDto<string> { export interface BookDto extends AuditedEntityDto<string> {
name?: string; name?: string;
type: BookType; type: BookType;
publishDate?: string; publishDate?: string;
price: number; price: number;
authorId?: string;
authorName?: string;
} }
export interface CreateUpdateBookDto { export interface CreateUpdateBookDto {
@ -13,4 +19,5 @@ export interface CreateUpdateBookDto {
type: BookType; type: BookType;
publishDate: string; publishDate: string;
price: number; price: number;
authorId?: string;
} }

+ 182
- 102
angular/src/app/proxy/generate-proxy.json View File

@ -1530,6 +1530,14 @@
"typeSimple": "[Acme.BookStore.Books.BookDto]" "typeSimple": "[Acme.BookStore.Books.BookDto]"
} }
}, },
{
"name": "GetAuthorLookupAsync",
"parametersOnMethod": [],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Acme.BookStore.Books.AuthorLookupDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Acme.BookStore.Books.AuthorLookupDto>"
}
},
{ {
"name": "GetAsync", "name": "GetAsync",
"parametersOnMethod": [ "parametersOnMethod": [
@ -1627,6 +1635,119 @@
} }
], ],
"actions": { "actions": {
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/app/book/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Acme.BookStore.Books.BookDto",
"typeSimple": "Acme.BookStore.Books.BookDto"
},
"allowAnonymous": false,
"implementFrom": "Volo.Abp.Application.Services.IReadOnlyAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.BookDto,System.Guid,Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto>"
},
"GetListAsyncByInput": {
"uniqueName": "GetListAsyncByInput",
"name": "GetListAsync",
"httpMethod": "GET",
"url": "api/app/book",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts",
"type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Sorting",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Acme.BookStore.Books.BookDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Acme.BookStore.Books.BookDto>"
},
"allowAnonymous": false,
"implementFrom": "Volo.Abp.Application.Services.IReadOnlyAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.BookDto,System.Guid,Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto>"
},
"GetAuthorLookupAsync": {
"uniqueName": "GetAuthorLookupAsync",
"name": "GetAuthorLookupAsync",
"httpMethod": "GET",
"url": "api/app/book/author-lookup",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Acme.BookStore.Books.AuthorLookupDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Acme.BookStore.Books.AuthorLookupDto>"
},
"allowAnonymous": false,
"implementFrom": "Acme.BookStore.Books.IBookAppService"
},
"GetBookDropDown": { "GetBookDropDown": {
"uniqueName": "GetBookDropDown", "uniqueName": "GetBookDropDown",
"name": "GetBookDropDown", "name": "GetBookDropDown",
@ -1639,7 +1760,7 @@
"type": "System.Collections.Generic.List<Acme.BookStore.Books.BookDto>", "type": "System.Collections.Generic.List<Acme.BookStore.Books.BookDto>",
"typeSimple": "[Acme.BookStore.Books.BookDto]" "typeSimple": "[Acme.BookStore.Books.BookDto]"
}, },
"allowAnonymous": null,
"allowAnonymous": false,
"implementFrom": "Acme.BookStore.Books.IBookAppService" "implementFrom": "Acme.BookStore.Books.IBookAppService"
}, },
"CreateAsyncByInput": { "CreateAsyncByInput": {
@ -1676,7 +1797,7 @@
"type": "Acme.BookStore.Books.BookDto", "type": "Acme.BookStore.Books.BookDto",
"typeSimple": "Acme.BookStore.Books.BookDto" "typeSimple": "Acme.BookStore.Books.BookDto"
}, },
"allowAnonymous": null,
"allowAnonymous": false,
"implementFrom": "Volo.Abp.Application.Services.ICreateAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.CreateUpdateBookDto>" "implementFrom": "Volo.Abp.Application.Services.ICreateAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.CreateUpdateBookDto>"
}, },
"UpdateAsyncByIdAndInput": { "UpdateAsyncByIdAndInput": {
@ -1733,7 +1854,7 @@
"type": "Acme.BookStore.Books.BookDto", "type": "Acme.BookStore.Books.BookDto",
"typeSimple": "Acme.BookStore.Books.BookDto" "typeSimple": "Acme.BookStore.Books.BookDto"
}, },
"allowAnonymous": null,
"allowAnonymous": false,
"implementFrom": "Volo.Abp.Application.Services.IUpdateAppService<Acme.BookStore.Books.BookDto,System.Guid,Acme.BookStore.Books.CreateUpdateBookDto>" "implementFrom": "Volo.Abp.Application.Services.IUpdateAppService<Acme.BookStore.Books.BookDto,System.Guid,Acme.BookStore.Books.CreateUpdateBookDto>"
}, },
"DeleteAsyncById": { "DeleteAsyncById": {
@ -1770,106 +1891,8 @@
"type": "System.Void", "type": "System.Void",
"typeSimple": "System.Void" "typeSimple": "System.Void"
}, },
"allowAnonymous": null,
"allowAnonymous": false,
"implementFrom": "Volo.Abp.Application.Services.IDeleteAppService<System.Guid>" "implementFrom": "Volo.Abp.Application.Services.IDeleteAppService<System.Guid>"
},
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/app/book/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Acme.BookStore.Books.BookDto",
"typeSimple": "Acme.BookStore.Books.BookDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Application.Services.IReadOnlyAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.BookDto,System.Guid,Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto>"
},
"GetListAsyncByInput": {
"uniqueName": "GetListAsyncByInput",
"name": "GetListAsync",
"httpMethod": "GET",
"url": "api/app/book",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts",
"type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Sorting",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Acme.BookStore.Books.BookDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Acme.BookStore.Books.BookDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Application.Services.IReadOnlyAppService<Acme.BookStore.Books.BookDto,Acme.BookStore.Books.BookDto,System.Guid,Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto>"
} }
} }
}, },
@ -5036,6 +5059,27 @@
} }
] ]
}, },
"Acme.BookStore.Books.AuthorLookupDto": {
"baseType": "Volo.Abp.Application.Dtos.EntityDto<System.Guid>",
"isEnum": false,
"enumNames": null,
"enumValues": null,
"genericArguments": null,
"properties": [
{
"name": "Name",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isRequired": false,
"minLength": null,
"maxLength": null,
"minimum": null,
"maximum": null,
"regex": null
}
]
},
"Acme.BookStore.Books.BookDto": { "Acme.BookStore.Books.BookDto": {
"baseType": "Volo.Abp.Application.Dtos.AuditedEntityDto<System.Guid>", "baseType": "Volo.Abp.Application.Dtos.AuditedEntityDto<System.Guid>",
"isEnum": false, "isEnum": false,
@ -5090,6 +5134,30 @@
"minimum": null, "minimum": null,
"maximum": null, "maximum": null,
"regex": null "regex": null
},
{
"name": "AuthorId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isRequired": false,
"minLength": null,
"maxLength": null,
"minimum": null,
"maximum": null,
"regex": null
},
{
"name": "AuthorName",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isRequired": false,
"minLength": null,
"maxLength": null,
"minimum": null,
"maximum": null,
"regex": null
} }
] ]
}, },
@ -5175,6 +5243,18 @@
"minimum": null, "minimum": null,
"maximum": null, "maximum": null,
"regex": null "regex": null
},
{
"name": "AuthorId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isRequired": false,
"minLength": null,
"maxLength": null,
"minimum": null,
"maximum": null,
"regex": null
} }
] ]
}, },


+ 14
- 16
angular/src/app/route.provider.ts View File

@ -14,38 +14,36 @@ function configureRoutes(routesService: RoutesService) {
iconClass: 'fas fa-home', iconClass: 'fas fa-home',
order: 1, order: 1,
layout: eLayoutType.application, layout: eLayoutType.application,
},
},
{ {
path: '/book-store',
name: '::Menu:BookStore',
iconClass: 'fas fa-book',
order: 2,
path: '/authors',
name: '::Menu:Authors',
iconClass: 'fas fa-user-plus',
order:2,
layout: eLayoutType.application, layout: eLayoutType.application,
requiredPolicy: 'BookStore.Books',
requiredPolicy: 'BookStore.Authors',
}, },
{ {
path: '/books', path: '/books',
name: '::Menu:Books',
parentName: '::Menu:BookStore',
name: '::Menu:Books',
iconClass: 'fas fa-book',
order: 3,
layout: eLayoutType.application, layout: eLayoutType.application,
requiredPolicy: 'BookStore.Books', requiredPolicy: 'BookStore.Books',
},
},
{ {
path: '/customer', path: '/customer',
name: 'Customer',
name: '::Menu:Customer',
iconClass: 'fas fa-user', iconClass: 'fas fa-user',
order: 2,
order: 4,
layout: eLayoutType.application, layout: eLayoutType.application,
requiredPolicy: 'BookStore.Customers', requiredPolicy: 'BookStore.Customers',
}, },
{ {
path: '/book-issue', path: '/book-issue',
name: 'book-issue',
name: '::Menu:BookIssue',
iconClass: 'fas fa-book', iconClass: 'fas fa-book',
order: 2,
order: 5,
layout: eLayoutType.application, layout: eLayoutType.application,
requiredPolicy: 'BookStore.BookIssued', requiredPolicy: 'BookStore.BookIssued',
}, },


+ 12
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/AuthorLookupDto.cs View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Books
{
public class AuthorLookupDto : EntityDto<Guid>
{
public string Name { get; set; }
}
}

+ 4
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/BookDto.cs View File

@ -14,5 +14,9 @@ namespace Acme.BookStore.Books
public DateTime PublishDate { get; set; } public DateTime PublishDate { get; set; }
public float Price { get; set; } public float Price { get; set; }
public Guid AuthorId { get; set; }
public string AuthorName { get; set; }
} }
} }

+ 3
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/CreateUpdateBookDto.cs View File

@ -20,5 +20,8 @@ namespace Acme.BookStore.Books
[Required] [Required]
public float Price { get; set; } public float Price { get; set; }
public Guid AuthorId { get; set; }
} }
} }

+ 2
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/IBookAppService.cs View File

@ -15,5 +15,7 @@ namespace Acme.BookStore.Books
CreateUpdateBookDto> //Used to create/update a book CreateUpdateBookDto> //Used to create/update a book
{ {
Task<List<BookDto>> GetBookDropDown(); Task<List<BookDto>> GetBookDropDown();
Task<ListResultDto<AuthorLookupDto>> GetAuthorLookupAsync();
} }
} }

+ 1
- 0
aspnet-core/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs View File

@ -17,6 +17,7 @@ public class BookStoreApplicationAutoMapperProfile : Profile
// CreateMap<List<Customer>, List<CustomerDto>>().ReverseMap(); // CreateMap<List<Customer>, List<CustomerDto>>().ReverseMap();
CreateMap<BookIssue, BookIssueDto>().ReverseMap(); CreateMap<BookIssue, BookIssueDto>().ReverseMap();
CreateMap<BookIssueList, BookIssueListDto>().ReverseMap(); CreateMap<BookIssueList, BookIssueListDto>().ReverseMap();
CreateMap<Author, AuthorLookupDto>();
/* You can configure your AutoMapper mapping configuration here. /* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations * Alternatively, you can split your mapping configurations


+ 116
- 24
aspnet-core/src/Acme.BookStore.Application/Books/BookAppService.cs View File

@ -1,43 +1,135 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks; using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Acme.BookStore.Permissions;
namespace Acme.BookStore.Books
namespace Acme.BookStore.Books;
[Authorize(BookStorePermissions.Books.Default)]
public class BookAppService :
CrudAppService<
Book, //The Book entity
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto>, //Used to create/update a book
IBookAppService //implement the IBookAppService
{ {
private readonly IAuthorRepository _authorRepository;
private readonly IRepository<Book, Guid> _bookRepository;
public BookAppService(
IRepository<Book, Guid> repository,
IAuthorRepository authorRepository)
: base(repository)
{
_authorRepository = authorRepository;
_bookRepository = repository;
GetPolicyName = BookStorePermissions.Books.Default;
GetListPolicyName = BookStorePermissions.Books.Default;
CreatePolicyName = BookStorePermissions.Books.Create;
UpdatePolicyName = BookStorePermissions.Books.Edit;
DeletePolicyName = BookStorePermissions.Books.Delete;
}
public override async Task<BookDto> GetAsync(Guid id)
{
//Get the IQueryable<Book> from the repository
var queryable = await Repository.GetQueryableAsync();
//Prepare a query to join books and authors
var query = from book in queryable
join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id
where book.Id == id
select new { book, author };
//Execute the query and get the book with author
var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query);
if (queryResult == null)
{
throw new EntityNotFoundException(typeof(Book), id);
}
var bookDto = ObjectMapper.Map<Book, BookDto>(queryResult.book);
bookDto.AuthorName = queryResult.author.Name;
return bookDto;
}
public override async Task<PagedResultDto<BookDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
//Get the IQueryable<Book> from the repository
var queryable = await Repository.GetQueryableAsync();
//Prepare a query to join books and authors
var query = from book in queryable
join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id
select new { book, author };
public class BookAppService :
CrudAppService<
Book, //The Book entity
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto>, //Used to create/update a book
IBookAppService //implement the IBookAppService
//Paging
query = query
.OrderBy(NormalizeSorting(input.Sorting))
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
//Execute the query and get a list
var queryResult = await AsyncExecuter.ToListAsync(query);
//Convert the query result to a list of BookDto objects
var bookDtos = queryResult.Select(x =>
{
var bookDto = ObjectMapper.Map<Book, BookDto>(x.book);
bookDto.AuthorName = x.author.Name;
return bookDto;
}).ToList();
//Get the total count with another query
var totalCount = await Repository.GetCountAsync();
return new PagedResultDto<BookDto>(
totalCount,
bookDtos
);
}
public async Task<ListResultDto<AuthorLookupDto>> GetAuthorLookupAsync()
{ {
private readonly IRepository<Book, Guid> _bookRepository;
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
var authors = await _authorRepository.GetListAsync();
return new ListResultDto<AuthorLookupDto>(
ObjectMapper.Map<List<Author>, List<AuthorLookupDto>>(authors)
);
}
private static string NormalizeSorting(string sorting)
{
if (sorting.IsNullOrEmpty())
{ {
_bookRepository = repository;
GetPolicyName = BookStorePermissions.Books.Default;
GetListPolicyName = BookStorePermissions.Books.Default;
CreatePolicyName = BookStorePermissions.Books.Create;
UpdatePolicyName = BookStorePermissions.Books.Edit;
DeletePolicyName = BookStorePermissions.Books.Delete;
return $"book.{nameof(Book.Name)}";
} }
public async Task<List<BookDto>> GetBookDropDown()
if (sorting.Contains("authorName", StringComparison.OrdinalIgnoreCase))
{ {
var cus = await _bookRepository.GetListAsync();
cus = cus == null ? new List<Book>() : cus;
return ObjectMapper.Map<List<Book>, List<BookDto>>(cus);
return sorting.Replace(
"authorName",
"author.Name",
StringComparison.OrdinalIgnoreCase
);
} }
return $"book.{sorting}";
}
public async Task<List<BookDto>> GetBookDropDown()
{
var cus = await _bookRepository.GetListAsync();
cus = cus == null ? new List<Book>() : cus;
return ObjectMapper.Map<List<Book>, List<BookDto>>(cus);
} }
} }

+ 8
- 1
aspnet-core/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json View File

@ -6,6 +6,8 @@
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.", "LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store", "Menu:BookStore": "Book Store",
"Menu:Books": "Books", "Menu:Books": "Books",
"Menu:Customer": "Customer",
"Menu:BookIssue": "Book Issue",
"Actions": "Actions", "Actions": "Actions",
"Close": "Close", "Close": "Close",
"Delete": "Delete", "Delete": "Delete",
@ -46,7 +48,12 @@
"Permission:BookIssued": "Book Issued Management", "Permission:BookIssued": "Book Issued Management",
"Permission:BookIssued.Create": "Creating new Issued Book", "Permission:BookIssued.Create": "Creating new Issued Book",
"Permission:BookIssued.Edit": "Editing the Issued Book", "Permission:BookIssued.Edit": "Editing the Issued Book",
"Permission:BookIssued.Delete": "Deleting the Issued Book"
"Permission:BookIssued.Delete": "Deleting the Issued Book",
"Menu:Authors": "Authors",
"Authors": "Authors",
"AuthorDeletionConfirmationMessage": "Are you sure to delete the author '{0}'?",
"BirthDate": "Birth date",
"NewAuthor": "New author"
} }
} }


+ 55
- 27
aspnet-core/src/Acme.BookStore.Domain/BookStoreDataSeederContributor.cs View File

@ -2,7 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Acme.BookStore.Books; using Acme.BookStore.Books;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -23,7 +23,7 @@ namespace Acme.BookStore
private readonly CustomerManager _customerManager; private readonly CustomerManager _customerManager;
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository, public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository,
IAuthorRepository authorRepository,
IAuthorRepository authorRepository,
AuthorManager authorManager, AuthorManager authorManager,
ICustomerRepository customerRepository, ICustomerRepository customerRepository,
CustomerManager customerManager CustomerManager customerManager
@ -40,48 +40,76 @@ namespace Acme.BookStore
public async Task SeedAsync(DataSeedContext context) public async Task SeedAsync(DataSeedContext context)
{ {
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
//if (await _bookRepository.GetCountAsync() <= 0)
//{
// await _bookRepository.InsertAsync(
// new Book
// {
// Name = "1984",
// Type = BookType.Dystopia,
// PublishDate = new DateTime(1949, 6, 8),
// Price = 19.84f
// },
// autoSave: true
// );
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
// await _bookRepository.InsertAsync(
// new Book
// {
// Name = "The Hitchhiker's Guide to the Galaxy",
// Type = BookType.ScienceFiction,
// PublishDate = new DateTime(1995, 9, 27),
// Price = 42.0f
// },
// autoSave: true
// );
//}
if (await _authorRepository.GetCountAsync() <= 0) if (await _authorRepository.GetCountAsync() <= 0)
{ {
await _authorRepository.InsertAsync(
var orwell = await _authorRepository.InsertAsync(
await _authorManager.CreateAsync( await _authorManager.CreateAsync(
"George Orwell", "George Orwell",
new DateTime(1903, 06, 25), new DateTime(1903, 06, 25),
"Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)." "Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."
) )
); );
await _authorRepository.InsertAsync(
var douglas = await _authorRepository.InsertAsync(
await _authorManager.CreateAsync( await _authorManager.CreateAsync(
"Douglas Adams", "Douglas Adams",
new DateTime(1952, 03, 11), new DateTime(1952, 03, 11),
"Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'." "Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'."
) )
); );
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
AuthorId = orwell.Id, // SET THE AUTHOR
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
AuthorId = douglas.Id, // SET THE AUTHOR
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
} }
if (await _customerRepository.GetCountAsync() <= 0) if (await _customerRepository.GetCountAsync() <= 0)


+ 2
- 0
aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs View File

@ -16,5 +16,7 @@ namespace Acme.BookStore.Books
public DateTime PublishDate { get; set; } public DateTime PublishDate { get; set; }
public float Price { get; set; } public float Price { get; set; }
public Guid AuthorId { get; set; }
} }
} }

+ 2
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs View File

@ -93,6 +93,8 @@ public class BookStoreDbContext :
BookStoreConsts.DbSchema); BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128); b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.HasOne<Author>().WithMany().HasForeignKey(x => x.AuthorId).IsRequired();
}); });
builder.Entity<Author>(b => builder.Entity<Author>(b =>


+ 2220
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240612062933_Added_AuthorId_To_Book.Designer.cs
File diff suppressed because it is too large
View File


+ 51
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240612062933_Added_AuthorId_To_Book.cs View File

@ -0,0 +1,51 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Acme.BookStore.Migrations
{
/// <inheritdoc />
public partial class Added_AuthorId_To_Book : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "AuthorId",
table: "AppBooks",
type: "uniqueidentifier",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_AppBooks_AuthorId",
table: "AppBooks",
column: "AuthorId");
migrationBuilder.AddForeignKey(
name: "FK_AppBooks_AppAuthors_AuthorId",
table: "AppBooks",
column: "AuthorId",
principalTable: "AppAuthors",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AppBooks_AppAuthors_AuthorId",
table: "AppBooks");
migrationBuilder.DropIndex(
name: "IX_AppBooks_AuthorId",
table: "AppBooks");
migrationBuilder.DropColumn(
name: "AuthorId",
table: "AppBooks");
}
}
}

+ 14
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs View File

@ -153,6 +153,9 @@ namespace Acme.BookStore.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<Guid>("AuthorId")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp") b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken() .IsConcurrencyToken()
.IsRequired() .IsRequired()
@ -197,6 +200,8 @@ namespace Acme.BookStore.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("AuthorId");
b.ToTable("AppBooks", (string)null); b.ToTable("AppBooks", (string)null);
}); });
@ -2016,6 +2021,15 @@ namespace Acme.BookStore.Migrations
b.ToTable("AbpTenantConnectionStrings", (string)null); b.ToTable("AbpTenantConnectionStrings", (string)null);
}); });
modelBuilder.Entity("Acme.BookStore.Books.Book", b =>
{
b.HasOne("Acme.BookStore.Authors.Author", null)
.WithMany()
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b =>
{ {
b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) b.HasOne("Volo.Abp.AuditLogging.AuditLog", null)


Loading…
Cancel
Save