web-dev-qa-db-ja.com

Spring MVCのDBで重複したエントリを処理し、例外をスローしたり、他の方法で処理するためのベストプラクティスは何ですか?

私は現在、Springスタック、Kotlinをプログラミング言語、Neo4jをストレージソリューションとして使用して、学校管理プロジェクトに取り組んでいます。

これがシナリオです。DBにClassエントリを作成しています。 ClassエンティティオブジェクトのプロパティがName: Nine, Section: A, Shift: Morning。 DBに保存するときは、同じプロパティを持つそのようなクラスがないことを確認する必要があります。

私の質問は、複製をチェックした後、マッサージを他の層またはクライアント側にどのように伝播すると想定するかです。重複または他の通常のフローが見つかったレイヤーにExceptionをスローしますか?

これが私が現在このシナリオを扱っているものです。 Kotlinコードを提供します。

コントローラ

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)
}

サービス層

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)
}

または、次のコードのように、コントローラからチェックするだけです

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

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

または、いくつかのDTOを使用して、サービスレイヤーとコントローラー間の通信を行うこともできます。そして、そのDTOには、見つかった重複エントリのステータスを通知できるいくつかのプロパティがあります。 ControllerAdviceが例外をよりエレガントに処理できることも知っています。

だから私はDBで重複したエントリを処理するための最良の方法は何か提案が必要でしょうか?

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

私の場合、DBに一意性制約を適用できない場合があります。たとえば、AクラスプロパティはName: Nine, Section: A, Shift: Morningおよび別のクラスプロパティName: Nine, Section: A, Shift: Day。この場合、制約はエンティティの値の組み合わせです。同じ組み合わせがDBに存在しないようにする必要があります。したがって、アプリケーション層から一意性をチェックする必要があるかもしれません。

2
Muztaba Hasanat

Springの機能と能力にこだわる価値のあるSpringとの作業。それらが要件と互換性がない場合を除き、その場合、Springの使用には疑問があります。

1。エラー処理

Springが提案したアプローチについてはすでに説明しました。 @ ControllerAdvice。エラー処理専用のコンポーネントを実装するか、コントローラで直接アノテーションを使用できます。

これにより、すべてのコントローラーのtry/catchブロックの重複が大幅に減少します。

2。エラーのスロー

それはよくある質問です:データ整合性制御のみをDBに委任しますか?

私は通常反対です。私にとって、DB制約は唯一の防衛線ではなく、最後の防衛線です。通常、制約はビジネスルールを反映するので、コードに沿ってこれらのルールを明示的かつ読み取り可能にすることに賛成です。

誤解しないでください。DBの制約を削除することはお勧めしません。 それらはでなければなりません。より多くのシステムがDBにアクセスしている場合は、予期しないデータ整合性違反を防ぐことができます。

Spring's Data Integrity Violation Exceptions、ビジネス例外、ドメインモデル例外のいずれを使用するかにかかわらず、#1を実装している場合、エラー処理によりこれらの違いは無関係になります。

例外がスローされる場所はユーザーによって異なります。これらの例外はビジネスに関連しているため、Controllersからは例外をスローしません。彼らはビジネスにできるだけ無知でなければなりません。

ドメインレイヤーから検証とエラースローを行うことをお勧めします。 DALに近い層。重要なことの1つは、実装との一貫性を保つことです。検証を行うことを決定した場合はいつでも、そのような戦略に固執してください。

3。検証

すべてのコレクションを取得する代わりに

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

行のcountを単純に行わないのはなぜですか?

classRepo.countByOrganizationName(...)

または

classRepo.existByOrganizationName(...)

4。質問

マッサージを他のレイヤーまたはクライアント側に伝播するにはどうすればよいですか?

依存します。上位層が独自の例外をスローするためにそれをキャッチしようとしている場合は、それを@ ControllerAdviceまで上げます。例外スタックトレースにトレースを追加しても、コードは改善されません。

しかし、上位層がそれを処理でき、失敗した実行のためのPlan B)がある場合、それをキャッチします。

Spring DAOの例外は、適切な理由でRuntimeExceptionであることがわかります;-)。

1
Laiv