2

I am currently working a School Management project using Spring stack, Kotlin as programming language and Neo4j for storage solution.

Here is the scenario, I am creating a Class entry in the DB. Lets assume the properties of the Class entity object are Name: Nine, Section: A, Shift: Morning. When I am going to save in DB I have to make sure that there is no such Class that has same properties.

My question is, after duplication check how I suppose to propagate the massage to the other layer or to the client side ? Throw an Exception in the layer where it found the duplication or any other normal flow ?

Here is what I am currently handling this scenario. Providing Kotlin code.

Controller

open fun post(@RequestBody cls: Course, request: HttpServletRequest): ResponseEntity<*> {        

    try {
        createdClass = classService.save(cls)
    }
    catch (ex: DuplicateCourseException) {            
        return responseConflict(cls)
    }catch (ex: DuplicateKeyException){
        return responseConflict(cls)
    }
    return responseOK(createdClass)
}

Service Layer

open fun save(course: Course): Course {
// Checking the DB 
    val foundDuplicate = classRepo.findListByOrganizationName(course.organization?.name)
            .filter {
                it.name == course.name
                it.section == course.section
                it.shift == course.shift
            }
            .isEmpty()
            .not()
    if (foundDuplicate) {
        // Custom Exception
        throw DuplicateCourseException("Duplicate Class Found")
    }
    return classRepo.save(course)
}

Or just checking from the Controller, like following code

open fun post(@RequestBody cls: Course, request: HttpServletRequest): ResponseEntity<*> {        

    if (classService.checkClassAlreadyExist(cls)) {
         return responseConflict(cls)
     }
   createdClass = classService.save(createdClass)         
   return responseOK(createdClass)
}

Or I could use some DTO to communicate between service layer and controller. And that DTO have some properties, that can tell the status of duplicate entry found. I am also aware that ControllerAdvice can handle Exception more elegantly.

So I would need suggestion what will be the best way to handle duplicate entry in DB ?

=======UPDATE=======

In my case apply uniqueness constraint in DB may not be possible. For example A class properties may be Name: Nine, Section: A, Shift: Morning and another class property Name: Nine, Section: A, Shift: Day. In this case constraint is the combination of the entity's values. Same combination should not be exist in DB. So I might have to check uniqueness from application layer.

  • As I suspected, Spring already accounts for duplicate records. See docs.spring.io/spring/docs/current/javadoc-api/org/…. You're required to maintain a Primary Key in your database, which will be included as a field in your DTO. – Robert Harvey Jun 15 '17 at 22:21
  • The best way is to apply a unique constraint to the database table so that no doubled entries exist... – Timothy Truckle Jun 15 '17 at 22:30
  • Please review the UPDATE section of my question. I've explained why I might need to check uniqueness from the application layer, not from the DB. – Muztaba Hasanat Jun 16 '17 at 20:53
  • The update sounds a composed Unique Key constraint, which can be defined in DB too. – Laiv Jun 16 '17 at 20:56
  • @Laiv But I am using Neo4j db. Still there is no such concept Unique Key constraint in Neo4j. – Muztaba Hasanat Jun 16 '17 at 21:09
1

Working with Spring worthwhile to stick to its features and capabilities. Unless they were incompatible with your requirements, in which case the usage of Spring would be questionable.

1. Error Handling

You already have mentioned the approach proposed by Spring. @ControllerAdvice. You can implement a dedicated component for error handling or use the annotations directly in the controllers.

This will reduce significantly the duplicity of try/catch blocks in all the Controllers.

2. Throwing errors

It's a common question: Do I delegate the data integrity control only to the DB?

I'm usually against. To me, the DB constraints are the last line of defence, not the only. Usually, the constraints reflect business rules so I'm in favour of making these rules explicit and readable along the code.

Don't get me wrong, I'm not suggesting to remove DB constraints. They must be. If there were more systems accessing to the DB, they will prevent you from unexpected data integrity violations.

Whether you use Spring's Data Integrity Violation Exceptions, business exceptions or domain model exceptions, if you have implemented #1, the error handling makes these differences irrelevant.

The place where the exceptions should be thrown depends on you. Due to these sort of exceptions are related to the business, I would not throw them from the Controllers. They should be as agnostic to the business as possible.

I would suggest doing the validations and the error throw from the domain layer. The layer closer to the DAL. One important thing is to be consistent with the implementation. Wherever you decide to do the validation, stick to such strategy.

3. The validation

Instead of retrieving all the collection

classRepo.findListByOrganizationName(course.organization?.name) 
  .filter { it.name == course.name 
       it.section == course.section 
       it.shift == course.shift }
   .isEmpty() .not()

Why don't you simply do a count of the rows?

classRepo.countByOrganizationName(...)

or

classRepo.existByOrganizationName(...)

4. The question

how I suppose to propagate the massage to the other layer or to the client side ?

Depends. If upper layers are just going to catch it for throwing its own exception, then just let it go up to the @ControllerAdvice. Feeding the exception stacktrace with more traces won't make your code better.

But, if the upper layers can deal with it and there's a Plan B for the failed execution, then catch it.

You will find that Spring DAO's exceptions are RuntimeException for a good reason ;-).

  • Note that if we want to be nipticking, the check of the user could fail if we try to create the same class at the same moment. So I would still put a constraint in Database. Currently my own design is to delegate to database simple checks like that, have them implemented in front for UI checks and handle business rule.rights check in the UI and the server side. But this is because I currently don't need a very clean handling of errors (<=> stacktrace is enough) in my server-side part since UI does that for me. – Walfrat Jun 16 '17 at 6:48
  • I agreed. DB constraints must be. I could also delegate many of the validations to the UI but these days, I only implement REST APIs so I can not trust in the UI because I don't know who is potentially consuming the API. So I do validations in every layer. Specific validations according to the layer, of course. So that when data reaches the lower layer the most common validations is isNull, isEmpty. Again I never trust in upper layers. No matter If they were typed down by me or by anybody else. (Maybe I'm kinda neurotic) – Laiv Jun 16 '17 at 7:22
  • I was talking with my senior colleague. In his opinion- insert duplicate entry is not an error. So throwing Exception is not reasonable. Rather should check with if-else. Is throwing an Exception in uniqueness constraint proper way to use Exception ? – Muztaba Hasanat Jun 16 '17 at 21:40
  • what you mean by "DB constraints are the last line of defense" ? Did you mean I should check constraint in application layer as well as in DB ? – Muztaba Hasanat Jun 16 '17 at 21:43
  • Yes. I implement the double check: db constraint + application validation. If Neo4J doesn't support db constraints (or atleast not the one you need) then you have no choice :-). Just decide where (the layer) to implement the validation. – Laiv Jun 16 '17 at 21:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.