Сущности JPA, сервисный уровень и репозитории: правильно ли я делаю?

я не совсем уверен, правильно ли я делаю это на своем уровне обслуживания/постоянства. В моем случае у меня есть четыре сущности: Пользователь, Категория, Инвестиции и Инвестиции:

Пользователь:

public class User implements Identifiable, Serializable {

@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, fetch = FetchType.LAZY, 
orphanRemoval = true)
private List<Investment> investmentList;

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "user_investment", joinColumns = { @JoinColumn(name = "user") }, 
inverseJoinColumns = { @JoinColumn(name = "investment") })
private List<Investment> publicInvestmentList;

@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, 
fetch = FetchType.LAZY, orphanRemoval = true)
private List<Category> categoryList;

...
}

Категория:

public class Category implements Identifiable, Serializable {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "owner", columnDefinition = "BIGINT(20)")
@NotNull
private User owner;

@OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
private List<Investment> investmentList;

...
}

Инвестиции:

public class Investment implements Identifiable, Serializable {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "owner")
@NotNull
private User owner;

@ManyToMany(mappedBy = "publicInvestmentList")
private List<User> publicUserList;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category")
@NotNull
private Category category;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "investmentrepeat")
@NotNull
private InvestmentRepeat investmentRepeat;

@OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
        CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "owninginvestmentrepeat", columnDefinition = "BIGINT(20)")
private InvestmentRepeat owningInvestmentRepeat;

...
}

Инвестиционный повтор:

public class InvestmentRepeat implements Identifiable, Serializable {
@OneToMany(mappedBy = "investmentRepeat", fetch = FetchType.LAZY)
private List<Investment> investmentList;

@OneToOne(mappedBy = "owningInvestmentRepeat", fetch = FetchType.LAZY)
@NotNull
private Investment parentInvestment;

...
}

Для каждого объекта существует класс обслуживания без сохранения состояния, например. Служба пользователей, служба категорий.

Мой первый вопрос: правильная ли моя функция для создания новой категории для пользователя и нужно ли мне обновлять сущность пользователя после сохранения категории?

КатегорияСервис:

 public Category createWithReferences(String categoryTitle, User owner,
        boolean deleteable) throws ServiceException,
        EntityPersistenceException {
    if (owner == null) {
        throw new ServiceException(getMessageService()
                .getMessageFromBundle("error.user_not_found_by_id"));
    }
    if (categoryTitle == null || categoryTitle.isEmpty()) {
        throw new ServiceException(getMessageService()
                .getMessageFromBundle("error.category.no_title"));
    }

    Category newCategory = new Category(categoryTitle, owner, deleteable);
    owner.addCategorie(newCategory);

    newCategory = this.repository.create(newCategory);
    userService.update(owner);

    return newCategory;
}

BaseEntityRepository реализует операции CRUD сущностей:

@Override
public T create(T obj) throws EntityPersistenceException {
    EntityTransaction tx = getEntityManager().getTransaction();
    tx.begin();
    try {
        getEntityManager().persist(obj);
        tx.commit();
    } catch (PersistenceException e) {
        if (tx.isActive()) {
            tx.rollback();
        }
        throw new EntityPersistenceException(
                "Could not create Object of Instance: "
                        + obj.getClass().getCanonicalName()
                        + "; ErrorMessage: " + e.getMessage());
    }

    return obj;
}

@Override
public T update(T obj) throws EntityPersistenceException {
    EntityTransaction tx = getEntityManager().getTransaction();
    tx.begin();
    try {
        obj = this.getEntityManager().merge(obj);
        tx.commit();
    } catch (PersistenceException e) {
        if (tx.isActive()) {
            tx.rollback();
        }
        throw new EntityPersistenceException(
                "Could not update Object of Instance: "
                        + obj.getClass().getCanonicalName()
                        + "; ErrorMessage: " + e.getMessage() + "; ID: "
                        + obj.getId());
    }
    return obj;
}

@Override
public void delete(T obj) throws EntityPersistenceException {
    EntityTransaction tx = getEntityManager().getTransaction();
    tx.begin();
    try {
        if (obj != null) {
            long id = 0;
            if (obj instanceof Identifiable) {
                id = ((Identifiable) obj).getId();
                T entity = getEntityManager().find(getType(), id);
                //entity = getEntityManager().merge(entity);
                getEntityManager().remove(entity);
                tx.commit();
            }
        }
    } catch (PersistenceException e) {
        if (tx.isActive()) {
            tx.rollback();
        }
        throw new EntityPersistenceException(
                "Could not delete Object of Instance: "
                        + obj.getClass().getCanonicalName()
                        + "; ErrorMessage: " + e.getMessage() + "; ID: "
                        + obj.getId());
    }
}

Когда я не обновляю пользователя после создания объекта, пользователь не содержит новую категорию, когда я обновляю его с помощью em.find(...), но новая категория создается в базе данных.

Другой момент: когда я сохраняю новую инвестицию с помощью InvestmentRepeat, тогда в db-table Investmentrepeat идентификатор родительской инвестиции каждый раз равен 0 или когда я удаляю аннотацию @NotNull, тогда идентификатор равен нулю. И правильно ли я добавляю инвестиции в категорию? Вот функция, в которой я создаю новую инвестицию:

Инвестиционный Сервис:

public Investment createWithReferences(User owner, String description,
        double amount, Date investDate, Category category,
        InvestmentRepeat investmentRepeat, boolean isParentInvestment)
        throws ServiceException, EntityPersistenceException {
    if (owner == null) {
        throw new ServiceException(getMessageService()
                .getMessageFromBundle("error.user_not_found_by_id"));
    }
    if (category == null) {
        throw new ServiceException(getMessageService()
                .getMessageFromBundle("error.category_is_null"));
    }
    if (investmentRepeat == null) {
        throw new ServiceException(getMessageService()
                .getMessageFromBundle("error.investmenterepeat_is_null"));
    }

    // Create investment
    Investment newInvestment = new Investment(investDate,
            new LocalDateTime(DateTimeZone.UTC), amount, description,
            owner, category, investmentRepeat);
    // add Investment to investmentRepeat and Category
    investmentRepeat.getInvestmentList().add(newInvestment);

    if (isParentInvestment) {
        investmentRepeat.setParentInvestment(newInvestment);
        newInvestment.setOwningInvestmentRepeat(investmentRepeat);
    }

    owner.findCategory(category).addInvestment(newInvestment);
    owner.addInvestment(newInvestment);

    // create investment
    newInvestment = this.create(newInvestment);

    // update Owner
    userService.update(owner);

    return newInvestment;
}

Я надеюсь, что кто-нибудь может сказать мне, какие ошибки я делаю и где мои знания о jpa неверны :)

Спасибо!


person juos    schedule 20.02.2016    source источник


Ответы (1)


Самый простой способ добавить категорию пользователю — сделать следующее.

  1. Убедитесь, что у вашего пользователя есть список категорий, иначе он заменит все категории только вашей последней.
  2. Добавить новую созданную категорию в список
  3. Обновите сущность пользователя, поскольку у вас есть каскадное отношение, категория будет сохранена, и будет выполнено сопоставление с пользователем.

Сейчас рассмотрим второй вопрос.

person alambrache    schedule 20.02.2016
comment
Спасибо за Ваш ответ! вы имеете в виду, что я должен прокомментировать newCategory = this.create(newCategory). Но когда я это делаю, вновь созданная категория в списке категорий пользователя имеет id = null. И когда я теперь добавляю вторую новую категорию в список и обновляю пользователя, то есть две категории с id = null и изменения идентификаторов в таблице категорий базы данных. - person juos; 21.02.2016
comment
Вы должны сделать так: Category newCategory = new Category(categoryTitle, owner, deleteable); owner.addCategorie(newCategory); userService.update(owner); - person alambrache; 22.02.2016
comment
Когда я делаю это, то, например. owner.getCategorList().get(0).getId() имеет значение null. Потому что будет выполнена операция слияния с категорией. NewCategory находится в базе данных, но имеет нулевой идентификатор в списке владельца, пока я не обновлю владельца:/ - person juos; 23.02.2016