There are multiple versions of this document. Pick the options that suit you best.

UI
Database

Web Application Development (with ABP Suite) Tutorial - Part 4: Book to Author Relation

In the previous parts, you have created the Book and Author entities (& generated code for all functionalities) for the book store application. However, currently there is no relation between these entities.

In this part, you will establish to one-to-many relation between the Book and Author entities.

Establishing Relations with ABP Suite

ABP Suite allows establishing both one-to-many and many-to-many relationships.

In this tutorial, you will only establish one-to-many relation between Book and Author entities. It's pretty straightforward to establish a relationship with ABP Suite. You should just need to navigate to the Navigations tab, and provide the metadata for navigation property (1-n) or navigation collection (n-n) relations.

Creating Book to Author Relationship

Please stop the application in ABP Studio's Solution Runner panel, because ABP Suite will make changes in the solution and it might need to build the solution in some steps and running the solution prevents to build it.

To establish one-to-many relations between Book and Author entities, select the Book entity from the entity selection box on the top-right of the CRUD page generation page:

Then, you can open the Navigations tab, and click the Add navigation property (1-n) button. After that, a navigation property model will open, and you can fill the fields like in the following figure:

Here is the details:

  • Selected the entity as Author. (ABP Suite will establish one-to-many relation between Book and Author entities with this configuration)
  • Set the property name as AuthorId, it will be set as foreign-key restriction in the database and all related database configurations will be made by ABP Suite.
  • Selected the display property as Name, this will be used in the dropdown component to set an author with a book & also it will be shown in the datatable of the Books page.
  • Also, made the relation required and set it filterable so books can be filterable by authors.

Note: You should delete all existing books in the database (if any), before the code generation. Because, a new foreign-key will be added to the books table and if there is any record in the table, then a new migration can't apply to the database and you may need to update the database manually.

After, specifying the metadata, you can click the Ok button to close the modal. Then, click the Save and generate button to start code generation process. ABP Suite will establish one-to-many relationship between the entities, and will generate all necessary code automatically:

It will take some time to complete the process. After the process is completed, you will see a success message, you can click the Ok button, and build & start the application by clicking the Run -> Build & Start button in the Solution Runner panel:

After the application is started, you can right-click and Browse on the application to open it in the ABP Studio's pre-integrated browser. You can first create an author and then create a book with the author for testing:

Also, notice that, in the advanced filter section, there is an Author dropdown, which you can use to filter books by authors (remember you set filterable while defining navigation property and thanks to that, ABP Suite generated the code accordingly):

Unit & Integration Tests

Since you completed the bookstore application, now we can check the generated tests, and run them to see if all of them pass or not.

There are several test projects in the solution:

Test projects slightly differs based on your UI and Database selection. For example, if you select MongoDB, then the Acme.BookStore.EntityFrameworkCore.Tests will be Acme.BookStore.MongoDB.Tests.

ABP Suite generated unit & integration tests, for the Book & Author entities. If you open the Test explorer in your IDE, you will see the following tests are generated:

ABP Suite generated tests for repository implementations & application service implementations for the generated code, if you enable Create unit & integration tests option, while creating the entity. Since, you already did that in the previous parts, it generated the all required tests for the entities.

Let's examine one of the generated test classes. Open the BooksAppServiceTests (under the test/Acme.BookStore.Application.Tests/Books/BookApplicationTests.cs) and check the CreateAsync method:

        [Fact]
        public async Task CreateAsync()
        {
            // Arrange
            var input = new BookCreateDto
            {
                Name = "6c3d1eda8bf04852b7bd5dfdbbd93224b252478c2e474d4c8faf24fa6b182168ca830d4f80e64e4a8e363f33e151d1d34a04be4709274c7fbf2214f9bb3a16c3",
                Type = default,
                PublishDate = new DateTime(2006, 8, 21),
                Price = 754882891,
                AuthorId = Guid.Parse("602460f6-df6e-456a-89d9-8c5870dfc583")
            };

            // Act
            var serviceResult = await _booksAppService.CreateAsync(input);

            // Assert
            var result = await _bookRepository.FindAsync(c => c.Id == serviceResult.Id);

            result.ShouldNotBe(null);
            result.Name.ShouldBe("6c3d1eda8bf04852b7bd5dfdbbd93224b252478c2e474d4c8faf24fa6b182168ca830d4f80e64e4a8e363f33e151d1d34a04be4709274c7fbf2214f9bb3a16c3");
            result.Type.ShouldBe(default);
            result.PublishDate.ShouldBe(new DateTime(2006, 8, 21));
            result.Price.ShouldBe(754882891);
        }

ABP Suite;

  • Create the BookCreateDto input DTO object, and fill its values with dummy data to simulate creating a book,
  • Then, it calls the IBooksAppService.CreateAsync method to create a book,
  • And finally, asserts the returned result to see if it's as expected or not.

Notice, also the AuthorId is set in the BookCreateDto object. At that point, you might ask yourself that I haven't created the author with that ID before, should not it throw exception?

No, it will not throw an exception, because ABP Suite also generates simple dummy data for the entities just for the tests! You can see the test data seed contributors under the Acme.BookStore.Domain.Tests project:

Here is the content of the AuthorsDataSeedContributor.SeedAsync method:

        public async Task SeedAsync(DataSeedContext context)
        {
            if (IsSeeded)
            {
                return;
            }

            await _authorRepository.InsertAsync(new Author
            (
                id: Guid.Parse("602460f6-df6e-456a-89d9-8c5870dfc583"),
                name: "d7bbb3bff0d54ad799477298c4572e9c05fd1175ab21416da17d0001e2b697cd7fef99fdb4414f26a05789667a97442bd65865510ba34c3599e874ccf08b45e4",
                birthDate: new DateTime(2010, 2, 11),
                shortBio: "3c2ff43c18e34d7b9ad3f1b9c444cbb000f90808d3774cb6b7702b957f472d74048597f93df744f6a6fdf507be428e016edec982f1174e09b124982cbc40156290ce6bc9fd7b49b4972741956cc847891cb55ad0942f4534b90aa0561d3e0c200340b613c7ad40c38b4b2f2c39298169a853473faed34341a130b31e1eb57e92"
            ));

            await _authorRepository.InsertAsync(new Author
            (
                id: Guid.Parse("6ea5a6b2-919e-4334-9728-13f4872e5e0e"),
                name: "fd332fb58f184716962b08fbaa92f1c3e0963d843ba34c82bb5409517f60da3727c43b05e8d4490f996c5d19265962e53a69ed5e3e144509aad1441e37ce5081",
                birthDate: new DateTime(2010, 6, 10),
                shortBio: "b7808946c46c42e3935c4d8203d82973cfb98c5d81644f1da4ce1e643767849e23e0eb12a92f48be8f7eec0c07aefa043721fdd3fea542cfa644d2b7d428dc8842647180ef8a47139e097f6674c4f0d86c46765c406042a2a858865cb112ecd78d9ef6f5843e444994641f924a38a2d24ee4e212d41444888d3c0861af0cf9dd"
            ));

            await _unitOfWorkManager!.Current!.SaveChangesAsync();

            IsSeeded = true;
        }

Since ABP Suite generated the test data seed contributors for each entity, you have initial data while testing your services. Also, as you would notice, the id in this example (602460f6-df6e-456a-89d9-8c5870dfc583) is same as the authorId field in the BooksAppServiceTests.CreateAsync method.

Let's execute all tests, and see the results:

Summary

So far, you have created the all functionality for the bookstore application without needing to write any single line of code. ABP Suite generated the entities, application services, UI components, unit & integration tests and more...

In the next part, you will write some code and modify the ABP Suite's generated code by writing the code in the specified hookpoints. Thanks to ABP Suite's Customized Code Support, in the next generation, our custom code will not be overridden and will be preserved.


Contributors


Last updated: December 09, 2024 Edit this page on GitHub

Was this page helpful?

Please make a selection.

To help us improve, please share your reason for the negative feedback in the field below.

Please enter a note.

Thank you for your valuable feedback!

Please note that although we cannot respond to feedback, our team will use your comments to improve the experience.

In this document
Community Talks

What’s New with .NET 9 & ABP 9?

21 Nov, 17:00
Online
Watch the Event
Mastering ABP Framework Book
Mastering ABP Framework

This book will help you gain a complete understanding of the framework and modern web application development techniques.

Learn More