JPA - Использование вставляемого / обновляемого - PullRequest
4 голосов
/ 21 июля 2010

Я пишу веб-сервис для поддержки базы данных. Я пытаюсь использовать JPA (EclipseLink) для классов сущностей. Однако в базе данных используются естественные первичные ключи, и поэтому существует вероятность того, что обновление полей идентификаторов завершится неудачей из-за ограничений внешнего ключа. Наш администратор баз данных предоставил функцию для обновления полей идентификаторов, которая создаст новую родительскую запись с обновленным идентификатором, обновит дочерние записи, чтобы они указывали на нового родителя, и удалил старого родителя.

Если бы поля идентификаторов можно было обновлять "в обычном режиме", у меня была бы такая ситуация:

@Entity
@Table(name = "PARENT")
public class Parent implements Serializable
{
    private static final long serialVersionUID = 1L;
    private String parent;
    private String attribute;
    private Set<Child> childs;

    public Parent()
    {
    }

    @Id
    @Column(name = "PARENT")
    public String getParent()
    {
        return this.parent;
    }

    public void setParent(String parent)
    {
        this.parent = parent;
    }

    @Column(name = "ATTRIBUTE")
    public String getAttribute()
    {
        return this.attribute;
    }

    public void setAttribute(String attribute)
    {
        this.attribute = attribute;
    }

    @OneToMany(mappedBy = "parentBean")
    public Set<Child> getChilds()
    {
        return this.childs;
    }

    public void setChilds(Set<Child> childs)
    {
        this.childs = childs;
    }
}

@Entity
@Table(name = "CHILD")
public class Child implements Serializable
{
    private static final long serialVersionUID = 1L;
    private String child;
    private String attribute;
    private Parent parentBean;

    public Child()
    {
    }

    @Id
    @Column(name = "CHILD")
    public String getChild()
    {
        return this.child;
    }

    public void setChild(String child)
    {
        this.child = child;
    }

    @Column(name = "ATTRIBUTE")
    public String getAttribute()
    {
        return this.attribute;
    }

    public void setAttribute(String attribute)
    {
        this.attribute = attribute;
    }

    @ManyToOne
    @JoinColumn(name = "PARENT")
    public Parent getParent()
    {
        return this.parent;
    }

    public void setParent(Parent parent)
    {
        this.parent = parent;
    }
}

У меня также есть класс GenericServiceBean с методом для вызова функций:

@Stateless
public class GenericServiceBean implements GenericService
{
    @PersistenceContext(unitName = "PersistenceUnit")
    EntityManager em;

    public GenericServiceBean()
    {
        // empty
    }

    @Override
    public <T> T create(T t)
    {
        em.persist(t);
        return t;
    }

    @Override
    public <T> void delete(T t)
    {
        t = em.merge(t);
        em.remove(t);
    }

    @Override
    public <T> T update(T t)
    {
        return em.merge(t);
    }

    @Override
    public <T> T find(Class<T> type, Object id)
    {
        return em.find(type, id);
    }

    . . . 

    @Override
    public String executeStoredFunctionWithNamedArguments(String functionName,
            LinkedHashMap<String, String> namedArguments)
    {
        Session session = JpaHelper.getEntityManager(em).getServerSession();

        StoredFunctionCall functionCall = new StoredFunctionCall();
        functionCall.setProcedureName(functionName);        
        functionCall.setResult("RESULT", String.class);

        for (String key : namedArguments.keySet())
        {
            functionCall.addNamedArgumentValue(key, namedArguments.get(key));
        }

        ValueReadQuery query = new ValueReadQuery();
        query.setCall(functionCall);

        String status = (String)session.executeQuery(query);

        return status;
    }
}

Если я установил поля идентификатора как недоступные для редактирования:

    @Id
    @Column(name = "PARENT", udpatable=false)
    public String getParent()
    {
        return this.parent;
    }

и вызов parent.setParent(newParent) будет ли это обновлять идентификатор в объекте сущности? Как это влияет на любые дочерние объекты? Будут ли они также обновляться (или нет)?

Другой сценарий, с которым я не знаю, как справиться, - это когда мне нужно обновить и идентификатор, и другой атрибут. Должен ли я вызвать функцию, которая обновляет (и фиксирует) идентификатор в базе данных, затем сделать вызовы для установки идентификатора и атрибута с помощью обычных методов set *, и тогда контекст постоянства будет только фиксировать изменение атрибута?

Возможно, это ситуация, когда JPA не подходит?

Любые советы по этому вопросу очень ценятся.

1 Ответ

5 голосов
/ 21 июля 2010

Если я установлю поля идентификаторов как недоступные для редактирования (...) и вызову parent.setParent(newParent), будет ли это обновлять идентификатор в объекте сущности?Как это влияет на любые дочерние объекты?Будут ли они также обновлены (или нет)?

updatable=false означает, что столбец не будет частью оператора SQL UPDATE независимо от того, что вы делаете на уровне объекта, поэтому Idне должен обновлятьсяИ я также испытываю желание сказать, что дочерние объекты не должны быть затронуты, тем более что вы ничего не каскадируете.

Другой сценарий, с которым я не знаю, как иметь дело, - это то, где мне нужнообновить как идентификатор, так и другой атрибут (...)

Что ж, я понимаю, что вам все равно придется вызывать функцию, поэтому я вызову ее сначала.

Возможно, это ситуация, когда JPA не подходит?

Я не уверен, что сырой SQL лучше справится с вашей ситуацией.На самом деле, сама идея смены первичных ключей звучит странно, если можно.

...