create account

Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images by johnesan

View this thread on: hive.blogpeakd.comecency.com
· @johnesan ·
$65.86
Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images
### Repository
https://github.com/dotnet/core

#### What Will I Learn?
- You will learn how to display related data of one entity in another.
- You will learn how to Edit/Update related data of one entity in another.
- You will learn how to store and display Selected Images of a Room in our Hotel Management System
- You will make use of HashSets in C#
- You will learn to use View Models

#### Requirements
- Basic knowledge of C# programming language
- Visual Studio 2017/ VS code/ Any suitable code editor
- [Previous Tutorial](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-8-working-with-jquery-and-ajax)


#### Difficulty
- Intermediate



#### Tutorial Contents
<center>![img8.PNG](https://cdn.steemitimages.com/DQmdzyxBai35vhf3AoN4nkAhy5pRJi4K9Nu92X9JhWCMPJR/img8.PNG)</center>

In the previous tutorial, we learnt how to manage images on the front end. We learnt how to select images for a room when creating or editing them, preview them and remove those we didn't like. However, all these actions were all taking place in the client's browser. Like every real world application, these changes should be persisted in a database. In this tutorial, we are going to write the server side code that handles this process and also write code to display this related data when requested.

### `ImageItem` Model
`Room` and `Image` are two distinct entities related in a ManyToMany relationship style, and as such there is no direct way of storing this relationship using a foreign key. We would require a new table. For that purpose, we create a new model `ItemImage`

```
public class ItemImage
    {
        public string ImageID { get; set; }
        public virtual Image Image { get; set; }
        public string ItemID { get; set; }
    }
```
I have called the model `ItemImage` because, despite working with the Room Entity at the moment, at some point we might want to create relationships between images and other model entities. It would be highly redundant to then create new models for each of them later on.

This model contains two foreign keys for the item in question, and the related image, as well as a navigation property for the image.

#### Adding an Itemimage DbSet 
Now to interact with the ItemImage table, we need a `DbSet` property defined in our db context

- ##### `ApplicationDbContext.cs`
```
public DbSet<ItemImage> ItemImageRelationships { get; set; }
```
 Using FluentAPI, we define the primary key for the table as a combination of the two foreign key properties, by overriding the `OnModelCreating` method
```
  protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            .
            .
            .          

            builder.Entity<ItemImage>()
                .HasKey(x => new { x.ItemID, x.ImageID });
        }
```   

#### Updating Our Database
Now that we have made changes to our ApplicationDbContext, we need to effect those changes on our database.

- Add a Migration
```
Add-Migration RoomFeatureRelationship
```

- Then run

```
Update-Database
```


Now check your database, If everything went well, you should see the new table ItemImage and the appropriate Foreign keys for the Joined Entities


### `UpdateRoomImagesList` Method
Now that we have created the ItemImage table in our db, let us add a method to handle the updating of the selected room images in our `GenericHotelService` class. To do that, as usual, we add the method signature definition in our `IGenericHotelService` interface
 
- ##### `IGenericHotelService.cs`
```
void UpdateRoomImagesList(Room room, string[] imageIDs);
```
This method definition will take in two parameters - the room to be updated and a string array of imageIDs.  

<hr/>

Next we implement this in our `GenericHotelService.cs` class:

- ##### `GenericHotelService.cs`
```
 public void UpdateRoomImagesList(Room room, string[] imagesIDs)
        {
            var PreviouslySelectedImages = _context.ItemImageRelationships.Where(x => x.ItemID == room.ID);
            _context.ItemImageRelationships.RemoveRange(PreviouslySelectedImages);
            _context.SaveChanges();

            if (imagesIDs != null)
            {
                foreach (var imageID in imagesIDs)
                {                    
                    try
                    {
                        var AllImagesIDs = new HashSet<string>(_context.Images.Select(x => x.ID));
                        if (AllImagesIDs.Contains(imageID))
                        {
                            _context.ItemImageRelationships.Add(new ItemImage
                            {
                                ImageID = imageID,
                                ItemID = room.ID
                            });
                        }
                    }     
                    catch(Exception e)
                    {
                        continue;
                    }
                }
                _context.SaveChanges();
            }
        }
```

#### Explanation for Code Above:
The first statement gets the previously linked Features to the room and thereafter removes those relationship from the RoomFeatureRelationships Table then call `SaveChanges()`.

```
 var PreviouslySelectedImages = _context.ItemImageRelationships.Where(x => x.ItemID == room.ID);
            _context.ItemImageRelationships.RemoveRange(PreviouslySelectedImages);
            _context.SaveChanges();
```
<hr/>

- Next, we check if the `imageIDs` array passed in is null. If not, we loop through the image IDs in the array, check our Images DbSet to ascertain if it is a valid ID linked to an image in the database, if yes, we create a relationship between the imageID and the item(room) ID. Thereafter, we SaveChanges() to persist our changes to the database.

```
 if (imagesIDs != null)
            {
                foreach (var imageID in imagesIDs)
                {                    
                    try
                    {
                        var AllImagesIDs = new HashSet<string>(_context.Images.Select(x => x.ID));
                        if (AllImagesIDs.Contains(imageID))
                        {
                            _context.ItemImageRelationships.Add(new ItemImage
                            {
                                ImageID = imageID,
                                ItemID = room.ID
                            });
                        }
                    }     
                    catch(Exception e)
                    {
                        continue;
                    }
                }
                _context.SaveChanges();
```


####    `Create` POST Action
Back at our create action in the `RoomController`, we need a way to get the image IDs selected, and pass them to this service method we just defined. Edit the `Create` post action and add the following code

```
   [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Number,RoomTypeID,Price,Available,Description,MaximumGuests")] Room room, string[] SelectedFeatureIDs, string[] imageIDs)
        {            
            if (ModelState.IsValid)
            {
              .
              .
              .
   _hotelService.UpdateRoomImagesList(room, imageIDs);
            }
            .
            .
            .
      }
```

Notice how we have  `string[] imageIDs` as part of the parameters for this method. This catches the value of all input elements with the name imageIDs.
We then pass this array of image IDs to the _hotelService `UpdateRoomImagesList method.

*Try to create a new room and select a list of images, then check the ItemImage table to confirm the additions.

### Displaying Room Related Data
Now that we have successfully added selected images for a room, let us display these images for the room in its details page. 

- ##### Create  `RoomFeaturesAndImagesViewModel`
To present this data as one model to the view, for display, we need a ViewModel. Recall that the `Room` entity has two foreign relationships with the `Feature` and `Image` entities. To fetch and return these related data to the view, we make use of a viewModel that has two properties, each of these entities.

```
    public class RoomFeaturesAndImagesViewModel
    {
        public List<Image> Images { get; set; }
        public List<Feature> Features { get; set; }
    }
```

<hr/>

Now lets add a method in our service class to handle this fetch process. Add the method signature definition in our IGenericHotelService interface

- ##### IGenericHotelService.cs
```
 Task<RoomFeaturesAndImagesViewModel> GetRoomFeaturesAndImagesAsync(Room room);
```
This method definition takes in a room as parameter and returns a `RoomFeaturesAndImagesViewModel` type.

Next we implement this in our GenericHotelService.cs class:

- ##### GenericHotelService.cs
```
  public async Task<RoomFeaturesAndImagesViewModel> GetRoomFeaturesAndImagesAsync(Room room)
        {
            var RoomImagesRelationship =  _context.ItemImageRelationships.Where(x => x.ItemID == room.ID);
            var images = new List<Image>();
            foreach(var RoomImage in RoomImagesRelationship)
            {
                var Image = await _context.Images.FindAsync(RoomImage.ImageID);
                images.Add(Image);
            }


            var RoomFeaturesRelationship = _context.RoomFeatureRelationships.Where(x => x.RoomID == room.ID);
            var features = new List<Feature>();
            foreach(var RoomFeature in RoomFeaturesRelationship)
            {
                var Feature = await _context.Features.FindAsync(RoomFeature.FeatureID);
                features.Add(Feature);
            }

            var ImagesAndFeatures = new RoomFeaturesAndImagesViewModel
            {
                Images = images,
                Features = features
            };
            return ImagesAndFeatures;
        }
```

#### Explanation For the Code Above
First, we fetch all the rows from the `ItemImagesRelationship` table with roomID of that supplied as argument to the method. Thereafter we create a list of images. Iterate through each Image from the selected RoomImages rows and add them to this list.
```
var RoomImagesRelationship =  _context.ItemImageRelationships.Where(x => x.ItemID == room.ID);
            var images = new List<Image>();
            foreach(var RoomImage in RoomImagesRelationship)
            {
                var Image = await _context.Images.FindAsync(RoomImage.ImageID);
                images.Add(Image);
            }
```

<br/>


We do the same for features, only this time, fetching from the `RoomFeatureRelationships` table.
```

 var RoomFeaturesRelationship = _context.RoomFeatureRelationships.Where(x => x.RoomID == room.ID);
            var features = new List<Feature>();
            foreach(var RoomFeature in RoomFeaturesRelationship)
            {
                var Feature = await _context.Features.FindAsync(RoomFeature.FeatureID);
                features.Add(Feature);
            }
```
<br/>

Lastly, we add create a new `RoomFeaturesAndImagesViewModel`  and set the properties appropriately to these list of images and features. Then we return this ViewModel.
```
  var ImagesAndFeatures = new RoomFeaturesAndImagesViewModel
            {
                Images = images,
                Features = features
            };
            return ImagesAndFeatures;
        }
```

#### `Details` Action
Back at our controller class, edit the Details action as follows:
```
 public async Task<IActionResult> Details(string id)
        {
           .
           .
           .
            var ImagesAndFeatures = await _hotelService.GetRoomFeaturesAndImagesAsync(room);
            ViewData["Features"] = ImagesAndFeatures.Features;
            ViewData["Images"] = ImagesAndFeatures.Images;
            return View(room);
        }
```

- Here, we make a call to the `GetRoomFeaturesAndImagesAsync()` that we just defined. We then send the features and images as ViewData to the view.


- #### Details View
We edit our details view to capture and reflect these new data.
```
>
<h4>Features</h4>
@foreach (var feature in ViewBag.Features as IEnumerable<Feature>)
{
    <p>@feature.Name</p>
    <p>@feature.Icon</p>
}

<h4>Images</h4>
@foreach (var image in ViewBag.Images as IEnumerable<Image>)
{
    <lmg src="@image.ImageUrl" asp-append-version="true" alt="@image.Name"/>
}
```

![](https://cdn.steemitimages.com/DQmbra1VodvBSPYQcXfJAfxJAAGGzQZbWDsHsTCyY2TxKjG/image.png)

<hr/>

### Curriculum
- [Building a Hotel Management System With ASP.NET Core(#1) - Introduction](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-1-introduction)
- [Building a Hotel Management System With ASP.NET Core(#2) - Building the Service Layer](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-2-building-the-service-layer)
- [Building a Hotel Management System With ASP.NET Core(#3) - Building the RoomType Controller Logic](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-3-building-the-roomtype-controller-logic)
- [Building a Hotel Management System With ASP.NET Core(#4) - Building the Room Controller Logic](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-4-building-the-room-controller-logic)
- [Building a Hotel Management System With ASP.NET Core(#5) - Complex Data Relationships(ManyToMany Relationship Linking)](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-5-complex-data-relationships-manytomany-relationship-linking)
- [Building a Hotel Management System With ASP.NET Core(#6) - Displaying and Updating Related Data](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-6-displaying-and-updating-related-data)
- [Building a Hotel Management System With ASP.NET Core(#7) - Working With Images](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-7-working-with-images)
- [Building a Hotel Management System With ASP.NET Core(#8) - Working with Jquery and AJAX](https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-8-working-with-jquery-and-ajax)


### Proof of Work Done
Github Repo for the tutorial solution:
https://github.com/Johnesan/TheHotelApplication
πŸ‘  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 55 others
properties (23)
authorjohnesan
permlinkbuilding-a-hotel-management-system-with-asp-net-core-9-storing-and-displaying-room-images
categoryutopian-io
json_metadata{"tags":["utopian-io","tutorials","asp-net","programming","dotnet"],"image":["https://cdn.steemitimages.com/DQmdzyxBai35vhf3AoN4nkAhy5pRJi4K9Nu92X9JhWCMPJR/img8.PNG","https://cdn.steemitimages.com/DQmbra1VodvBSPYQcXfJAfxJAAGGzQZbWDsHsTCyY2TxKjG/image.png"],"links":["https://github.com/dotnet/core","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-8-working-with-jquery-and-ajax","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-1-introduction","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-2-building-the-service-layer","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-3-building-the-roomtype-controller-logic","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-4-building-the-room-controller-logic","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-5-complex-data-relationships-manytomany-relationship-linking","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-6-displaying-and-updating-related-data","https://steemit.com/utopian-io/@johnesan/building-a-hotel-management-system-with-asp-net-core-7-working-with-images","https://github.com/Johnesan/TheHotelApplication"],"app":"steemit/0.1","format":"markdown"}
created2018-07-06 22:23:33
last_update2018-07-06 22:23:33
depth0
children5
last_payout2018-07-13 22:23:33
cashout_time1969-12-31 23:59:59
total_payout_value49.866 HBD
curator_payout_value15.997 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length14,511
author_reputation5,467,095,998,728
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,711,050
net_rshares33,139,236,056,191
author_curate_reward""
vote details (119)
@portugalcoin ·
Thank you for your contribution.

- Please enter the source of the first image.
- Put some comments on your code, plus the explanation you've already made.

It would be interesting to see a backend for upload image of each room and description.

Your contribution has been evaluated according to [Utopian policies and guidelines](https://join.utopian.io/guidelines), as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, [click here](https://review.utopian.io/result/8/11113303).

---- 
Need help? Write a ticket on https://support.utopian.io/. 
Chat with us on [Discord](https://discord.gg/uTyJkNm). 
[[utopian-moderator]](https://join.utopian.io/)
properties (22)
authorportugalcoin
permlinkre-johnesan-building-a-hotel-management-system-with-asp-net-core-9-storing-and-displaying-room-images-20180707t124838195z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"links":["https://join.utopian.io/guidelines","https://review.utopian.io/result/8/11113303","https://support.utopian.io/","https://discord.gg/uTyJkNm","https://join.utopian.io/"],"app":"steemit/0.1"}
created2018-07-07 12:48:39
last_update2018-07-07 12:48:39
depth1
children0
last_payout2018-07-14 12:48:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length736
author_reputation598,828,312,571,988
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,777,186
net_rshares0
@steemitboard ·
Congratulations @johnesan! You received a personal award!

<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@johnesan/birthday1.png</td><td>1 Year on Steemit</td></tr></table>

<sub>_[Click here to view your Board of Honor](https://steemitboard.com/@johnesan)_</sub>


> Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-johnesan-20181218t082605000z
categoryutopian-io
json_metadata{"image":["https://steemitboard.com/img/notify.png"]}
created2018-12-18 08:26:06
last_update2018-12-18 08:26:06
depth1
children0
last_payout2018-12-25 08:26:06
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length502
author_reputation38,975,615,169,260
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id77,006,157
net_rshares0
@steemitboard ·
Congratulations @johnesan! You received a personal award!

<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@johnesan/birthday2.png</td><td>Happy Birthday! - You are on the Steem blockchain for 2 years!</td></tr></table>

<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@johnesan) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=johnesan)_</sub>


###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-johnesan-20191218t085145000z
categoryutopian-io
json_metadata{"image":["https://steemitboard.com/img/notify.png"]}
created2019-12-18 08:51:45
last_update2019-12-18 08:51:45
depth1
children0
last_payout2019-12-25 08:51:45
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length620
author_reputation38,975,615,169,260
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id93,516,348
net_rshares0
@tngflx ·
Lol I was planning to do the same!! It's great that you have started it :) Now i can have some guidance where to start!
πŸ‘  
properties (23)
authortngflx
permlinkre-johnesan-building-a-hotel-management-system-with-asp-net-core-9-storing-and-displaying-room-images-20180709t011740816z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"app":"steemit/0.1"}
created2018-07-09 01:17:42
last_update2018-07-09 01:17:42
depth1
children0
last_payout2018-07-16 01:17:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length119
author_reputation17,396,455,988,713
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,962,810
net_rshares0
author_curate_reward""
vote details (1)
@utopian-io ·
Hey @johnesan
**Thanks for contributing on Utopian**.
We’re already looking forward to your next contribution!

**Want to chat? Join us on Discord https://discord.gg/h52nFrV.**

<a href='https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1'>Vote for Utopian Witness!</a>
properties (22)
authorutopian-io
permlinkre-building-a-hotel-management-system-with-asp-net-core-9-storing-and-displaying-room-images-20180707t222508z
categoryutopian-io
json_metadata"{"app": "beem/0.19.42"}"
created2018-07-07 22:25:09
last_update2018-07-07 22:25:09
depth1
children0
last_payout2018-07-14 22:25:09
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length300
author_reputation152,955,367,999,756
root_title"Building a Hotel Management System With ASP.NET Core(#9) - Storing and Displaying Room Images"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,829,793
net_rshares0