Deleting Categories

To round out our coverage of all the CRUD operations, we now turn to deleting entities with Hibernate and Spring. Here we find another opportunity to talk about collection mapping in Hibernate. In particular, we discover the implications of using lazy loading versus eager loading.

To utilize Github with this course, you can download the Github desktop client for your system or use the command line interface provided with Git.

Clone this repository to your machine using the Github desktop client, or using the following command:

git clone git@github.com:treehouse/giflib-hibernate.git

To update your local repository to match a video's starting point, you can use the git checkout command in combination with the stage and video number. For example, to update your local repository to match the starting point of Stage 5, Video 4, you'd use the following:

git checkout -f s5v4

Notice the use of the -f option. This forces Git to override all local changes, so be aware: this will cause any changes you made to be lost.

Typo in Thymeleaf Template

In the video, in category/form.html, there is a typo in the conditional display of the delete button. The video shows a th:id attribute, when it should be a th:if attribute. Here is the entire <div> tag as it should appear:

<div class="row delete" th:if="${category.id != null}">

Custom Exceptions in the Service Layer

Instead of coding the logic for preventing the deletion of a non-empty category in the controller, you can put this in the service layer. The advantage of moving this logic to the service layer would be that any client calling upon the service could leverage that same logic, whether it's the controller we're using in our MVC app or a REST controller that powers an API utilizing the same service. In either case we want the logic to be the same: prevent users from deleting categories that aren't empty.

To accomplish this, you could move your if statement into the CategoryServiceImpl.delete method:

Then, in your controller, you can either use a try/catch block in place of the if block, or if you'd like to dive deeper into Spring you can configure controller methods to handle certain exception. See this blog post for more information.

0:00

With the update operations for
both categories and

0:02

GIFs complete,
it's time to move on to deleting entities.

0:05

This usually works in
an application in one of two ways.

0:09

When users are asked to delete something,
either one,

0:12

they're asked to confirm that
they really want to delete.

0:15

Or two, a growing trend is that
users aren't asked if they're sure.

0:19

But rather presented with an option to
undo after clicking a delete button.

0:24

Both of these approaches require more
advanced code than we'll cover, so

0:27

we won't offer either option.

0:30

But know that a live,
functioning application should always have

0:34

one of these two options in case something
was clicked or tapped by mistake.

0:39

Let's start by deleting a category.

0:41

Now we're gonna make a decision
here that categories can

0:44

only be deleted when there are no
GIFs present in that category.

0:48

That way, we don't wipe away an entire
population of GIFs with one measly click.

0:53

If we intend on allowing our users
the option of deleting a category.

0:57

We better make sure our HTML produces
the functional ability to do so.

1:02

Our category form has a delete button, but
a submit currently doesn't do anything.

1:07

Let's change this, I'm gonna open
the category form.html template.

1:14

There it is.

1:15

Now if you scroll down to
the delete button markup,

1:18

you'll notice it's a form
in need of some attention.

1:21

Right here.

1:22

The form's opening tag has nothing in it,
no attributes,

1:26

no action attribute, no method attribute.

1:28

Let's change that.

1:30

First, let's make sure that submitting
the form will post to the correct URL.

1:35

I'll do that by adding
a th:action attribute.

1:39

And here I'll have timely process the URL
by including the at sign and curly braces.

1:46

Now this value needs to be /categories/
whatever the category id is /delete.

1:52

In order for

1:53

our controller method that we have in
our controller to capture it correctly.

1:57

So I will use Thymeleaf
concatenation to make that happen.

2:02

So this will be /categories/ whatever

2:06

the category id is and then /delete.

2:12

And finally, let me add that method
attribute here and list it as a post.

2:19

One thing to be careful with here.

2:21

Remember how we're using this form
that is this Thymeleaf template for

2:24

both adding a category and
editing a category?

2:27

Well, when this template is used for
adding a category,

2:30

that category won't have an id yet, so
this right here will cause an error.

2:36

Even more, we probably don't even want
a delete button to appear when a new

2:40

category is being added.

2:41

That wouldn't make much sense.

2:43

So let's add a th if attribute
to check for a null ID and

2:47

I will place that right here.

2:49

Th if, so here I'll check to see
if the categories id is null,

2:55

category.id and I'll check to
see if it's not equal to null.

3:00

If it's not equal to null,
then I do want to display this whole div.

3:05

So cool, we're all set with our markup.

3:08

Next, let's move to the category
controller to the method that will capture

3:11

this form submission.

3:13

So I will open the CategoryController.

3:18

And the method we're looking for
is the delete category method,

3:23

that should be at the bottom.

3:24

But we have a couple tasks
here to take care of,

3:28

first we need to check to see if
the category is empty and if so deleted.

3:31

In any case,
we need to add a flash message and

3:34

redirect to the appropriate page.

3:35

So first, let's grab the category
object using the category services

3:40

findById method.

3:42

So right here,
I'll do that actually above this comment,

3:49

I'll call it cat and
let's use the category services again.

3:54

FindById method and
there's the categoryId right there, so

3:57

let's use that parameter value categoryId,
perfect.

4:03

Next, let's make sure to account for

4:06

the possibility that
the category is not empty.

4:10

So I'll say if(cat.getGifs().size()
is greater than zero.

4:19

So here, if it's greater than zero,

4:21

I don't want to allow that
category to be deleted.

4:25

So what I'll do here is
I'll add a flash message

4:28

that says something to the effect of
only empty categories can be deleted.

4:32

So I'll use that redirectAttributes.

4:35

And you'll notice here,

4:36

I don't have a parameter that is
a redirectAttributes parameter.

4:39

Let's go add one.

4:43

RedirectAttributes, right, now it's there.

4:48

So here, to this object I will
add a Flash Attribute called

4:54

flash and into it,
I'll create a new flash message object.

4:58

New Flash Message.

5:01

And remember we put the text of
the message first and then the status.

5:04

So only empty categories can be deleted,
all right.

5:12

And we will use the status
of FAILURE on that one.

5:20

And if that happens,
let's redirect back to that edit form.

5:26

So we'll say return String.format and

5:30

redirect:/, that'll be categories/

5:35

whatever the categorId happens to be,
/edit.

5:42

We'll get that categoryId from
the parameter value here.

5:46

CategoryId, cool.

5:48

Now if we make it past this if block,

5:50

let's use the categoryService
to delete that category.

5:55

We called it cat.

5:58

And we should also add a success
message as a flash message.

6:03

So we'll do that again,
redirectAttributes.addFlashAttribute,

6:08

we called it flash.

6:10

New FlashMessage and
we'll say Category deleted.

6:19

And that'll have a status of SUCCESS.

6:26

Add my semicolon there, wonderful.

6:28

And now let's redirect the browser back to
the /URI instead of returning null here.