How to solve this: application model and engine model mismatch when using JPA persistence?

戏子无情 提交于 2019-12-12 04:56:28

问题


The title may seems confusing, but it's not easy to describe the question in few words. Let me explain the situation:

  1. We have a web application project, and a calculation engine project. The web application collect user input and use the engine to generate some result, and represent to user. Both user input, engine output and other data will be persisted to DB using JPA.

  2. The engine input and output consist of objects in tree structure, example like:

    Class InputA {
      String attrA1;
      List<InputB> inputBs;
    }
    
    Class InputB {
      String attrB1;
      List<InputC> inputCs;
    }
    
    Class InputC {
      String attrC1;
    }
    

The engine output is in similar style.

  1. The web application project handle the data persistence using JPA. We need to persist the engine input and output, as well as some other data that related to the input and output. Such data can be seem as extra fields to certain class. For example:

We want to persist extra field, so it looks like:

    Class InputBx extends InputB{
      String attrBx1;
    }

    Class InputCx extends InputC{
      String attrCx1;
    }

In Java OO world, this works, we can store a list of InputBx in InputA, and store a list of InputCx in InputBx because of the inheritance.

But we meet trouble when using JPA to persist the extended objects.

First of all, it requires the engine project to make their class become JPA entities. The engine was working fine by itself, it accept correct input and generate correct output. It doesn't smell good to force their model to become JPA entities when another project try to persist the model.

Second, the JPA doesn't accept the inherited objects when using InputA as the entry. From JPA point of view, it only know that InputA contains a list of InputB, and not possible to persist/retrieve a list of InputBx in object of InputA.


When trying to solve this, we had come up 2 ideas, but neither one satisfied us:

idea 1: Use composition instead inheritance, so we still persist the original InputA and it's tree structure include InputB and InputC:

    Class InputBx{
      String attrBx1;
      InputB inputB;
    }
    Class InputCx{
      String attrCx1;
      InputC inputC;
    }

So the original input object tree can be smoothly retrieved, and InputBx and InputCx objects needs to be retrieved using the InputB and InputC objects in the tree as references.

The good thing is that no matter what changes made to the structure of the original input class tree (such as change attribute name, add/remove attributes in the classes), the extended class InputBx and InputCx and their attributes automatically synchronized.

The drawback is that this structure increases the calls to the database, and the model is not easy to use in the application(both back end and front end). Whenever we want related information of InputB or InputC, we need to manually code to search the corresponding object of InputBx and InputCx.

idea 2: Manually make mirror classes to form a similar structure of the original input classes. So we created:

    Class InputAx {
      String attrA1;
      List<InputBx> inputBs;
    }

    Class InputBx {
      String attrB1;
      List<InputCx> inputCs;
      String attrBx1;
    }

    Class InputCx {
      String attrC1;
      String attrCx1;
    }

We could use this as model of the web application, and the JPA entities as well. Here's what we could get:

  1. Now the engine project can be set free, it doesn't need to bind to how the other projects persist these input/output objects. The engine project is independant now.

  2. The JPA persistence works just fluent, no extra calls to database is required

  3. The back end and front end UI just use this model to get both original input objects and related information with no effort. When trying use engine to perform calculation, we can use a mapping mechanism to transfer between the original objects and extended objects.

The drawback is also obvious:

  1. There is duplication in the class structure, which is not desired from the OO point of view.

  2. When considering it as DTO to reduce the database calls, it can be claimed as anti-pattern when using DTO in local transfer.

  3. The structure is not automatically synchronized with the original model. So if there are any changes made to the original model, we need to manually update this model as well. If some developers forget to do this, there will be some not-easy-to-find defects.


I'm looking for the following help:

  1. Is there any existing good/best practices or patterns to solve similar situation we meet? Or any anti-patterns that we should try to avoid? References to web articles are welcome.

  2. If possible, can you comment on the idea 1 and idea 2, from the aspect of OO design, Persistence practices, your experience, ect.

I will be grateful for your help.

来源:https://stackoverflow.com/questions/29552786/how-to-solve-this-application-model-and-engine-model-mismatch-when-using-jpa-pe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!