Как использовать другой EntityManager на основе условия во время выполнения?

#jpa #ejb #cdi

#jpa #ejb #cdi

Вопрос:

Моя конфигурация выглядит следующим образом:

Абстрактный класс:

 public abstract class AbstractFacade<T> {

    private Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    // other methods create(T), edit(T), ...
  

Ejb, который расширяет абстрактный класс (у меня есть много других EJB и около 12 различных единиц сохранения):

 @Stateless
public class FilesDao extends AbstractFacade<Files> {

    @PersistenceContext(unitName = "myfirstPU")
    private EntityManager firstEm;

    @PersistenceContext(unitName = "mysecondPU")
    private EntityManager secondEm;

    // i have more than two persistenceUnit ... 

    @Override
    protected EntityManager getEntityManager() {
         return firstEm; // or secondEm based on condition
    }

    public FilesDao() {
         super(Files.class);
    }

    public Files findByFileref(String inFileRef) {
         try {
             Query q = firstEm.createNamedQuery("Files.findByFileref"); // or secondEm based on condition
             q.setParameter("fileref", inFileRef);
             Files file = (Files) q.getSingleResult();
             return file;
        } catch (NoResultException e) {
             return null;
        }
    }
  

Я хочу использовать FilesDao следующим образом :

 @Stateless
@LocalBean
public class FileBusiness {

    @EJB
    FilesDao fileDao;

    public void myMethod(){
    if(condition1){
         //use the FileDao with the EnityManager **firstEm**
    }
    else if(condition2){
        //use the FileDao with the EnityManager **secondtEm**
    }
    ...

}
  

Есть ли способ добиться этого?

Я читал об использовании CDI с методом produce.

Комментарии:

1. Поскольку кажется, что вам нужно динамически решать, какой из EM выбирать при каждом вызове, я бы просто перепроектировал AbstractFacade.getEntityManager() , чтобы принимать аргумент условия и на основе этого возвращать соответствующий EM. Производители CDI, вероятно, не помогут вам здесь, поскольку они предназначены для того, чтобы, когда вам нужно, после внедрения решить, что вводить (тогда как вам нужно каждый раз динамически выбирать другое).

Ответ №1:

Создание CDI не так сложно, смотрите Следующий пример.

Следующие классы являются аннотациями с определителем CDI, которые используются для различения реализаций.

 @Retention(RetentionPolicy.RUNTIME)
@Target({ TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR }) 
@Qualifier 
public @interface MyfirstPUQualifier {  }

@Retention(RetentionPolicy.RUNTIME)
@Target({ TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR }) 
@Qualifier 
public @interface MysecondPUQualifier {  }
  

Ниже приведен компонент CDI, который внедряет разные EntityManagers и реализует методы производителя, делая два EntityManagers доступными для CDI, различаемые с помощью CDI-квалификаторов

 @ApplicationScoped
class MYProducer {
    @PersistenceContext(unitName = "myfirstPU")
    private EntityManager firstEm;

    @PersistenceContext(unitName = "mysecondPU")
    private EntityManager secondEm;

    @Produces
    @RequestScoped
    @MyfirstPUQualifier
    public EntityManager produceMyfirstPU(){
        return firstEm;
    }


    @Produces
    @RequestScoped
    @MysecondPUQualifier
    public EntityManager produceMysecondPU(){
        return secondEm;
    }
}
  

Ниже показан компонент CDI, внедряющий оба EntityManager. Это может быть извлечено в абстрактный базовый класс, потому что, возможно, это необходимо и другим DAO.

 @Stateless
public class FileDao {

    @Inject
    @MyfirstPUQualifier
    private EntityManager emFirst;

    @Inject
    @MysecondPUQualifier
    private EntityManager emSecond;

    public void myDaoMEthod(){
        final EntityManager em = getEntityManager();
        ...
    }

    private EntityManager getEntityManager(){
        if(condition1){
            return emFirst;
        }
        else if(condition2){
            return emSecond;
        }
    }
}
  

Никто не может использовать компонент FileDao, не заботясь о том, какой EntityManager использовать, потому что в любом случае это не должно решаться в этом компоненте

 @Stateless
@LocalBean
public class FileBusiness {

    @EJB
    FilesDao fileDao;

    public void myMethod(){
        // FileDao will decide what entity manager to use
        fileDao.doStruff();
    }
}