Подход к (общему) репозиторию DDD с JPA/Spring: он выглядит неправильно?

Я новичок в DDD и JPA.

Я работаю над общим репозиторием с JPA и Spring. Мне очень нравятся подходы, изложенные в статьях DDD: Общий репозиторий и Шаблоны реализации JPA: объекты доступа к данным. Моя цель — создать идеальный репозиторий в доменно-ориентированном дизайне с помощью JPA и Spring.

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

public interface IInternalGenericRepository<K, E> {
    List<E> read(String query, Object[] params);
    void persist(E entity);
    void remove(E entity);
}

public class InternalGenericRepository<K, E> implements IInternalGenericRepository<K, E> {

    // Injected through DI in Spring
    @PersistenceContext
    private EntityManager em;

    private final Class<E> entityClass;

    public List<E> read(String query, Object[] params) {
        Query q = em.createQuery(query);
        for (int i = 0; i < params.length; i++) {
            q.setParameter(i + 1, params[i]);
        }
        return q.getResultList();
    }

    public void persist(E entity) {
        em.persist(entity);
    }

    // ...
}

Тогда репозиторий для определенного объекта (например, организации) выглядит следующим образом.

public interface IOrganizationRepository {
    List<Organization> organizationByCityName(String city);

    void create(Organization o);
}


@Repository
public class OrganizationRepository implements IOrganizationRepository {

    @Autowired
    IInternalGenericRepository<Long, Organization> internalRepository;

    public List<Organization> organizationByCityName(String city) {
        Object[] params = new Object[1];
        params[0] = city;
        return internalRepository.read("select o from Organization o where o.city.name like ?1",
                params);
    }

    @Override
    public void create(Organization o) {
        internalRepository.persist(o);
    }
}

Похоже, это хороший способ реализовать репозиторий DDD с помощью JPA и Spring. Затем OrganizationRepository внедряется в мой уровень сервисов.

Я хотел бы иметь внешние взгляды, чтобы избежать недостатков или неправильного понимания. Что вы думаете и как его можно улучшить?

Спасибо.


Изменить:

  • @Autowired во внутреннем репозитории - спасибо axtavt за указание.
  • read() можно улучшить

person Community    schedule 10.02.2010    source источник


Ответы (1)


Прежде всего, это не сработает, потому что Spring не может внедрить EntityManager во внутренний объект, созданный с помощью new. Итак, вы должны написать что-то вроде этого:

public class OrganizationRepository implements IOrganizationRepository { 

    @PersistenceContext
    public void setEntityManager(EntityManager em) {
        internalRepository.em = em;
    }
    ...
}

Также ваш метод read выглядит слишком общим. Он пропускает некоторые важные варианты использования, такие как getSigleResult и setFirstResult/setMaxResults.

Лично я предпочитаю подход ко второй статье, потому что, используя композицию, вы получите EntityManager в OrganizationRepository, чтобы реализовать функции, пропущенные в IInternalGenericRepository.

person axtavt    schedule 10.02.2010
comment
спасибо за Ваш ответ. Цель состоит в том, чтобы внедрить EntityManager только во внутренний общий репозиторий. Я не хочу вводить его в каждый конкретный репозиторий. Должен быть способ сделать это с помощью Spring. - person rochb; 11.02.2010
comment
Что касается второго подхода, у него есть большое ограничение, которое объясняется в первой статье: некоторые объекты имеют разные требования, чем другие. Объект клиента нельзя удалить, PurchaseOrder нельзя обновить, а объект ShoppingCart можно только создать. Когда кто-то использует общий интерфейс IRepository‹T›, это, очевидно, вызывает проблемы в реализации. - person rochb; 11.02.2010