diff --git a/docs/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/Tutorials/AspNetCore-Mvc/Part-I.md index 169fdc7a2f..084d5da408 100644 --- a/docs/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/Tutorials/AspNetCore-Mvc/Part-I.md @@ -30,12 +30,12 @@ Define [entities](../../Entities.md) in the **domain layer** (`Acme.BookStore.Do using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Entities.Auditing; namespace Acme.BookStore { [Table("Books")] - public class Book : AggregateRoot + public class Book : AuditedAggregateRoot { [Required] [StringLength(128)] @@ -50,8 +50,10 @@ namespace Acme.BookStore } ```` -* ABP has two fundamental base classes for entities: `AggregateRoot` and `Entity`. **Aggregate Roots** are one of the concepts of the **Domain Driven Design (DDD)**. See [entity document](../../Entities.md) for details and best practices. -* Used **data annotation attributes** in this code. You could use EF Core's [fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling) instead. +* ABP has two fundamental base classes for entities: `AggregateRoot` and `Entity`. **Aggregate Root** is one of the **Domain Driven Design (DDD)** concepts. See [entity document](../../Entities.md) for details and best practices. +* `Book` entity inherits `AuditedAggregateRoot` which adds some auditing properties (`CreationTime`, `CreatorId`, `LastModificationTime`... etc.) on top of the `AggregateRoot` class. +* `Guid` is the **primary key type** of the `Book` entity. +* Used **data annotation attributes** in this code for EF Core mappings. You could use EF Core's [fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling) instead. #### BookType Enum @@ -117,15 +119,14 @@ Create a DTO class named `BookDto` into the `Acme.BookStore.Application` project ````C# using System; -using System.ComponentModel.DataAnnotations; using Volo.Abp.Application.Dtos; +using Volo.Abp.AutoMapper; namespace Acme.BookStore { - public class BookDto : EntityDto + [AutoMapFrom(typeof(Book))] + public class BookDto : AuditedEntityDto { - [Required] - [StringLength(128)] public string Name { get; set; } public BookType Type { get; set; } @@ -138,6 +139,45 @@ namespace Acme.BookStore ```` * **DTO** classes are used to transfer data between the presentation layer and the application layer. See the [Data Transfer Objects document](../../Data-Transfer-Objects.md) for details. +* `BookDto` is used to transfer a book data to the presentation layer to show a book information on the UI. +* `BookDto` is derived from the `AuditedEntityDto` which has audit properties just like the `Book` defined above. +* `[AutoMapFrom(typeof(Book))]` is used to create AutoMapper mapping from the `Book` class to the `BookDto` class. Thus, you can automatically convert `Book` objects to `BookDto` objects (instead of manually copy all properties). + +#### CreateUpdateDto + +Create a DTO class named `CreateUpdateDto` into the `Acme.BookStore.Application` project: + +````c# +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.AutoMapper; + +namespace Acme.BookStore +{ + [AutoMapTo(typeof(Book))] + public class CreateUpdateBookDto + { + [Required] + [StringLength(128)] + [Display(Name = "Name")] + public string Name { get; set; } + + [Display(Name = "Type")] + public BookType Type { get; set; } = BookType.Undefined; + + [Display(Name = "PublishDate")] + public DateTime PublishDate { get; set; } + + [Display(Name = "Price")] + public float Price { get; set; } + } +} +```` + +* This DTO class is used to get book information from the user interface. +* Each property has a `[Display]` property which sets the label on the form for the related input. It's also integrated to the localization system. +* It defines data annotation attributes (like `[Required]`) to define validations for the properties. +* Each property has a `[Display]` property which sets the label on UI forms for the related inputs. It's also integrated to the localization system. The same DTO will be used as View Model. That's why it defines that attribute. You may find incorrect to use DTOs as View Models. You could use a separated view model class, but we thought it's practical and makes the sample project less complex. #### IBookAppService @@ -145,20 +185,28 @@ First, define an interface named `IBookAppService` for the book application serv ````C# using System; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; namespace Acme.BookStore { - public interface IBookAppService : IAsyncCrudAppService + public interface IBookAppService : + IAsyncCrudAppService< //Defines CRUD methods + BookDto, //Used to show books + Guid, //Primary key of the book entity + PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books + CreateUpdateBookDto, //Used to create a new book + CreateUpdateBookDto> //Used to update a book { } } + ```` * Defining interfaces for application services is not required by the framework. However, it's suggested as a good practice. * `IAsyncCrudAppService` defines common CRUD methods: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` and `DeleteAsync`. It's not required to extend it. Instead you could inherit from the empty `IApplicationService` interface and define your own methods. -* There are some variations of the `IAsyncCrudAppService`. In this sample, the first generic parameter, `BookDto`, is the DTO used for service methods and the second parameter, `Guid`, is the type of the primary key of the entity. +* There are some variations of the `IAsyncCrudAppService` where you can use a single DTO or separated DTOs for each method. #### BookAppService @@ -166,12 +214,16 @@ Implement the `IBookAppService` as named `BookAppService`: ````C# using System; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; namespace Acme.BookStore { - public class BookAppService : AsyncCrudAppService, IBookAppService + public class BookAppService : + AsyncCrudAppService, + IBookAppService { public BookAppService(IRepository repository) : base(repository) @@ -182,9 +234,9 @@ namespace Acme.BookStore } ```` -* `BookAppService` is derived from `AsyncCrudAppService` which implements all CRUD methods defined above. -* `BookAppService` injects `IRepository` which is the default repository created for the `Book` entity. See the [repository document](../../Repositories.md). -* `BookAppService` uses `IObjectMapper` to convert `Book` objects to `BookDto` objects and vice verse. Startup template uses the [AutoMapper](http://automapper.org/) library as the mapping provider. Since you haven't defined any mapping configuration, AutoMapper's [inline mapping](http://automapper.readthedocs.io/en/latest/Inline-Mapping.html) feature is used to automatically configure the mapping. This works fine if both classes have identical properties, but may cause to problems if they not. See the [AutoMapper integration document](../../AutoMapper-Integration.md) for details. +* `BookAppService` is derived from `AsyncCrudAppService<...>` which implements all CRUD methods defined above. +* `BookAppService` injects `IRepository` which is the default repository created for the `Book` entity. ABP automatically creates repositories for each aggregate root (or entity). See the [repository document](../../Repositories.md). +* `BookAppService` uses `IObjectMapper` to convert `Book` objects to `BookDto` objects and `CreateUpdateBookDto` objects to `Book` objects. Startup template uses the [AutoMapper](http://automapper.org/) library as the mapping provider. You defined mappings using the `AutoMapFrom` and `AutoMapTo` attributes above. See the [AutoMapper integration document](../../AutoMapper-Integration.md) for details. ### Auto API Controllers @@ -229,14 +281,7 @@ You can see the **book list** returned from the server. Let's **create a new book** using the `create` function: ````js -acme.bookStore.book.create({ - name: 'Foundation', - type: 7, - publishDate: '1951-05-24', - price: 21.5 -}).done(function (result) { - console.log('successfully created the book with id: ' + result.id); -}); +acme.bookStore.book.create({ name: 'Foundation', type: 7, publishDate: '1951-05-24', price: 21.5 }).done(function (result) { console.log('successfully created the book with id: ' + result.id); }); ```` You should see a message in the console something like that: @@ -336,6 +381,7 @@ Change the `Pages/Books/Index.cshtml` as following: @L["Type"] @L["PublishDate"] @L["Price"] + @L["CreationTime"] @@ -370,11 +416,15 @@ $(function() { }, { targets: 2, - data: "price" + data: "publishDate" }, { targets: 3, - data: "publishDate" + data: "price" + }, + { + targets: 4, + data: "creationTime" } ] }); diff --git a/docs/Tutorials/AspNetCore-Mvc/Part-II.md b/docs/Tutorials/AspNetCore-Mvc/Part-II.md index 0791fef352..e1ad9edf27 100644 --- a/docs/Tutorials/AspNetCore-Mvc/Part-II.md +++ b/docs/Tutorials/AspNetCore-Mvc/Part-II.md @@ -29,8 +29,6 @@ Create a new razor page, named `CreateModal.cshtml` under the `Pages/Books` fold Open the `CreateModal.cshtml.cs` file (`CreateModalModel` class) and replace with the following code: ````C# -using System; -using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; @@ -40,7 +38,7 @@ namespace Acme.BookStore.Pages.Books public class CreateModalModel : AbpPageModel { [BindProperty] - public CreateBookViewModel Book { get; set; } + public CreateUpdateBookDto Book { get; set; } private readonly IBookAppService _bookAppService; @@ -51,75 +49,15 @@ namespace Acme.BookStore.Pages.Books public async Task OnPostAsync() { - ValidateModel(); - - var bookDto = ObjectMapper.Map(Book); - await _bookAppService.CreateAsync(bookDto); - + await _bookAppService.CreateAsync(Book); return NoContent(); } - - public class CreateBookViewModel - { - [Required] - [StringLength(128)] - [Display(Name = "Name")] - public string Name { get; set; } - - [Display(Name = "Type")] - public BookType Type { get; set; } = BookType.Undefined; - - [Display(Name = "PublishDate")] - public DateTime PublishDate { get; set; } - - [Display(Name = "Price")] - public float Price { get; set; } - } } } ```` -* `CreateBookViewModel` is a nested class that will be used to create and post the form. - * Each property has a `[Display]` property which sets the label on the form for the related input. It's also integrated to the localization system. - * Each property has data annotations for validation which is used for validation in the client side and the server side and automatically localized. * `[BindProperty]` attribute on the `Book` property binds post request data to this property. - -##### AutoMapper Configuration - -`OnPostAsync` method maps `CreateBookViewModel` object to `BookDto` object (which is accepted by the `BookAppService.CreateAsync` method). - -Open the `BookStoreWebAutoMapperProfile` class and add the mapping: - -````C# -using Acme.BookStore.Pages.Books; -using AutoMapper; -using Volo.Abp.AutoMapper; - -namespace Acme.BookStore -{ - public class BookStoreWebAutoMapperProfile : Profile - { - public BookStoreWebAutoMapperProfile() - { - CreateMap() - .Ignore(x => x.Id); - } - } -} - -```` - -Thus, AutoMapper will create the mapping configuration between classes and will ignore the `Id` property of the `BookDto` class (to satisfy the configuration validation - see below). - -##### AutoMapper Configuration Validation - -AutoMapper has a [configuration validation feature](http://automapper.readthedocs.io/en/latest/Configuration-validation.html) which is not enabled for the startup template by default. If you want to perform validation, go to the `BookStoreWebModule` class, find the `ConfigureAutoMapper` method and change the `AddProfile` line as shown below: - -````c# -options.AddProfile(validate: true); -```` - -It's up to you to use validation or not. It can prevent mapping mistakes, but comes with a cost of configuration. See [AutoMapper's documentation](http://automapper.readthedocs.io/en/latest/Configuration-validation.html) to fully understand it. +* This class simply injects the `IBookAppService` in its constructor and calls the `CreateAsync` method in the `OnPostAsync` handler. ##### CreateModal.cshtml @@ -139,8 +77,7 @@ Open the `CreateModal.cshtml` file and paste the code below: - - + ```` diff --git a/docs/images/bookstore-book-list.png b/docs/images/bookstore-book-list.png index 34cec48c66..f531e6f457 100644 Binary files a/docs/images/bookstore-book-list.png and b/docs/images/bookstore-book-list.png differ diff --git a/docs/images/bookstore-books-table.png b/docs/images/bookstore-books-table.png index 0493791918..3cc8d7ca18 100644 Binary files a/docs/images/bookstore-books-table.png and b/docs/images/bookstore-books-table.png differ diff --git a/docs/images/bookstore-new-book-button.png b/docs/images/bookstore-new-book-button.png index 6f1cb321bf..dfd4b5d8aa 100644 Binary files a/docs/images/bookstore-new-book-button.png and b/docs/images/bookstore-new-book-button.png differ diff --git a/samples/BookStore/src/Acme.BookStore.Application/BookAppService.cs b/samples/BookStore/src/Acme.BookStore.Application/BookAppService.cs index be48dd689d..1d5e844f30 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/BookAppService.cs +++ b/samples/BookStore/src/Acme.BookStore.Application/BookAppService.cs @@ -1,12 +1,16 @@ using System; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; namespace Acme.BookStore { - public class BookAppService : AsyncCrudAppService,IBookAppService + public class BookAppService : + AsyncCrudAppService, + IBookAppService { - public BookAppService(IRepository repository) + public BookAppService(IRepository repository) : base(repository) { diff --git a/samples/BookStore/src/Acme.BookStore.Application/BookDto.cs b/samples/BookStore/src/Acme.BookStore.Application/BookDto.cs index 2e29512859..42581b95fb 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/BookDto.cs +++ b/samples/BookStore/src/Acme.BookStore.Application/BookDto.cs @@ -1,13 +1,12 @@ using System; -using System.ComponentModel.DataAnnotations; using Volo.Abp.Application.Dtos; +using Volo.Abp.AutoMapper; namespace Acme.BookStore { - public class BookDto : EntityDto + [AutoMapFrom(typeof(Book))] + public class BookDto : AuditedEntityDto { - [Required] - [StringLength(128)] public string Name { get; set; } public BookType Type { get; set; } diff --git a/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs b/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs index 1a2fa2e316..fb7bc32d37 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs +++ b/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Acme.BookStore.Permissions; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.AutoMapper; using Volo.Abp.Identity; using Volo.Abp.Modularity; @@ -18,6 +19,11 @@ namespace Acme.BookStore options.DefinitionProviders.Add(); }); + services.Configure(options => + { + options.AddProfile(); + }); + services.AddAssemblyOf(); } } diff --git a/samples/BookStore/src/Acme.BookStore.Application/BookStoreWebAutoMapperProfile.cs b/samples/BookStore/src/Acme.BookStore.Application/BookStoreWebAutoMapperProfile.cs new file mode 100644 index 0000000000..d1132f8086 --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.Application/BookStoreWebAutoMapperProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace Acme.BookStore +{ + public class BookStoreApplicationAutoMapperProfile : Profile + { + public BookStoreApplicationAutoMapperProfile() + { + //add your custom AutoMapper configuration + } + } +} diff --git a/samples/BookStore/src/Acme.BookStore.Application/CreateUpdateBookDto.cs b/samples/BookStore/src/Acme.BookStore.Application/CreateUpdateBookDto.cs new file mode 100644 index 0000000000..018b67bdbf --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.Application/CreateUpdateBookDto.cs @@ -0,0 +1,24 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.AutoMapper; + +namespace Acme.BookStore +{ + [AutoMapTo(typeof(Book))] + public class CreateUpdateBookDto + { + [Required] + [StringLength(128)] + [Display(Name = "Name")] + public string Name { get; set; } + + [Display(Name = "Type")] + public BookType Type { get; set; } = BookType.Undefined; + + [Display(Name = "PublishDate")] + public DateTime PublishDate { get; set; } + + [Display(Name = "Price")] + public float Price { get; set; } + } +} \ No newline at end of file diff --git a/samples/BookStore/src/Acme.BookStore.Application/IBookAppService.cs b/samples/BookStore/src/Acme.BookStore.Application/IBookAppService.cs index 3960e5e5c0..054dce0ce3 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/IBookAppService.cs +++ b/samples/BookStore/src/Acme.BookStore.Application/IBookAppService.cs @@ -1,9 +1,16 @@ using System; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; namespace Acme.BookStore { - public interface IBookAppService : IAsyncCrudAppService + public interface IBookAppService : + IAsyncCrudAppService< //Defines CRUD methods + BookDto, //Used to show books + Guid, //Primary key of the book entity + PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books + CreateUpdateBookDto, //Used to create a new book + CreateUpdateBookDto> //Used to update a book { } diff --git a/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj b/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj index 4879145029..ccbeeea56e 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj +++ b/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj @@ -7,6 +7,7 @@ + diff --git a/samples/BookStore/src/Acme.BookStore.Domain/Book.cs b/samples/BookStore/src/Acme.BookStore.Domain/Book.cs index be5292aee3..3119b7f257 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/Book.cs +++ b/samples/BookStore/src/Acme.BookStore.Domain/Book.cs @@ -1,12 +1,12 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Entities.Auditing; namespace Acme.BookStore { [Table("Books")] - public class Book : AggregateRoot + public class Book : AuditedAggregateRoot { [Required] [StringLength(128)] diff --git a/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/en.json b/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/en.json index 570a858be3..3011e0dd3a 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/en.json +++ b/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/en.json @@ -10,6 +10,7 @@ "Type": "Type", "PublishDate": "Publish Date", "Price": "Price", + "CreationTime": "Creation Time", "NewBook": "New book", "Books": "Books" } diff --git a/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/tr.json b/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/tr.json index ee71c2ccc1..c99d490575 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/tr.json +++ b/samples/BookStore/src/Acme.BookStore.Domain/Localization/BookStore/tr.json @@ -10,6 +10,7 @@ "Type": "Tür", "PublishDate": "Yayınlanma Tarihi", "Price": "Fiyat", + "CreationTime": "Oluşturulma zamanı", "NewBook": "Yeni kitap", "Books": "Kitaplar" } diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj index 0cea8959b2..900f401938 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj @@ -5,10 +5,6 @@ Acme.BookStore - - - - diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.Designer.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.Designer.cs similarity index 98% rename from samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.Designer.cs rename to samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.Designer.cs index 89843d2d16..07bf86d485 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.Designer.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.Designer.cs @@ -1,25 +1,24 @@ // using System; -using System.Collections.Generic; +using Acme.BookStore.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Acme.BookStore.EntityFrameworkCore; namespace Acme.BookStore.Migrations { [DbContext(typeof(BookStoreDbContext))] - [Migration("20180528221424_Initial")] + [Migration("20180701195241_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.0-preview2-30571") + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.cs similarity index 99% rename from samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.cs rename to samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.cs index 7722e7bd64..4fefa64288 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180528221424_Initial.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195241_Initial.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; namespace Acme.BookStore.Migrations diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.Designer.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.Designer.cs similarity index 97% rename from samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.Designer.cs rename to samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.Designer.cs index a06036b726..7990831265 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.Designer.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.Designer.cs @@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Acme.BookStore.Migrations { [DbContext(typeof(BookStoreDbContext))] - [Migration("20180628193337_Created_Book_Entity")] + [Migration("20180701195424_Created_Book_Entity")] partial class Created_Book_Entity { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -26,6 +26,14 @@ namespace Acme.BookStore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("CreationTime"); + + b.Property("CreatorId"); + + b.Property("LastModificationTime"); + + b.Property("LastModifierId"); + b.Property("Name") .IsRequired() .HasMaxLength(128); diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.cs similarity index 77% rename from samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.cs rename to samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.cs index 1e6d5ec0ed..5fd4adb7d0 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180628193337_Created_Book_Entity.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20180701195424_Created_Book_Entity.cs @@ -12,6 +12,10 @@ namespace Acme.BookStore.Migrations columns: table => new { Id = table.Column(nullable: false), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), Name = table.Column(maxLength: 128, nullable: false), Type = table.Column(nullable: false), PublishDate = table.Column(nullable: false), diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs index d1693bb99b..122a306295 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs @@ -24,6 +24,14 @@ namespace Acme.BookStore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("CreationTime"); + + b.Property("CreatorId"); + + b.Property("LastModificationTime"); + + b.Property("LastModifierId"); + b.Property("Name") .IsRequired() .HasMaxLength(128); diff --git a/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs b/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs index 64373ef0a7..239e3e9635 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs +++ b/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs @@ -1,6 +1,4 @@ -using Acme.BookStore.Pages.Books; -using AutoMapper; -using Volo.Abp.AutoMapper; +using AutoMapper; namespace Acme.BookStore { @@ -8,8 +6,7 @@ namespace Acme.BookStore { public BookStoreWebAutoMapperProfile() { - CreateMap() - .Ignore(x => x.Id); + //add your custom AutoMapper configuration } } } diff --git a/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/CreateModal.cshtml.cs b/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/CreateModal.cshtml.cs index a57bd82441..0e9ed1ba72 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/CreateModal.cshtml.cs +++ b/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/CreateModal.cshtml.cs @@ -1,5 +1,3 @@ -using System; -using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; @@ -9,7 +7,7 @@ namespace Acme.BookStore.Pages.Books public class CreateModalModel : AbpPageModel { [BindProperty] - public CreateBookViewModel Book { get; set; } + public CreateUpdateBookDto Book { get; set; } private readonly IBookAppService _bookAppService; @@ -20,29 +18,8 @@ namespace Acme.BookStore.Pages.Books public async Task OnPostAsync() { - ValidateModel(); - - var bookDto = ObjectMapper.Map(Book); - await _bookAppService.CreateAsync(bookDto); - + await _bookAppService.CreateAsync(Book); return NoContent(); } - - public class CreateBookViewModel - { - [Required] - [StringLength(128)] - [Display(Name = "Name")] - public string Name { get; set; } - - [Display(Name = "Type")] - public BookType Type { get; set; } = BookType.Undefined; - - [Display(Name = "PublishDate")] - public DateTime PublishDate { get; set; } - - [Display(Name = "Price")] - public float Price { get; set; } - } } } \ No newline at end of file diff --git a/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/Index.cshtml b/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/Index.cshtml index 94a74470ed..6233c32c8d 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/Index.cshtml +++ b/samples/BookStore/src/Acme.BookStore.Web/Pages/Books/Index.cshtml @@ -28,6 +28,7 @@ @L["Type"] @L["PublishDate"] @L["Price"] + @L["CreationTime"] diff --git a/samples/BookStore/src/Acme.BookStore.Web/wwwroot/pages/books/index.js b/samples/BookStore/src/Acme.BookStore.Web/wwwroot/pages/books/index.js index fed19a78cc..160c6327d9 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/wwwroot/pages/books/index.js +++ b/samples/BookStore/src/Acme.BookStore.Web/wwwroot/pages/books/index.js @@ -12,11 +12,15 @@ }, { targets: 2, - data: "price" + data: "publishDate" }, { targets: 3, - data: "publishDate" + data: "price" + }, + { + targets: 4, + data: "creationTime" } ] });