Можно ли изменить загруженное поле перед загрузкой? - PullRequest
0 голосов
/ 09 ноября 2011

Я использую встроенный OpenEJB в одном модульном тесте. Тест не работает. Когда я отлаживал, я обнаружил, что лениво извлеченное поле ведет себя странно.

Это действительно возможно? Если поле уже загружено, все идет как обычно:

//field == "something from db"
field = "ahoj";
//field == "ahoj"

Но если поле не было загружено:

//field == null
field = "ahoj";
//field == null

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

Итак, мой вопрос: существует ли какое-то правило, что непоправимое поле управляемого объекта не может быть назначено? И если есть подобное правило, как изменить значение поля, не извлекая его из базы данных?

1 Ответ

0 голосов
/ 10 ноября 2011

Ответ, конечно, да.Но что происходило вчера?

Проблема была в контексте постоянства и, возможно, также в имени метода.Поле не было обновлено в его установщике.Контекст постоянства связан с транзакцией.Таким образом, если вам нужно обновить и сохранить несколько полей, вы должны выполнить все операции в рамках одной транзакции.Вы должны запустить транзакцию, вызвать установщики вызовов для объекта и вызвать метод обновления для сессионного компонента, управляющего доступом к объектам.

@Basic(fetch=FetchType.LAZY)
String field;

@Override
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public String getFiled() {
    return field;
}

@Override
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void setText(String text) {
    //other code
    this.field = text;
    //other code
}

Получатель может вызываться или не вызываться в транзакции.Но установщик должен быть вызван в рамках существующей транзакции.Тот же атрибут транзакции применяется к методу обновления сессионного компонента.Кроме того, нам нужен метод reattach(), чтобы убедиться, что мы работаем с объектом в правильном постоянном контексте.

@Stateless
class AccessBean implements Accessor {
    @PersistenceContext(unitName = "MyUnit")
    private EntityManager manager;

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public TheEntity update(TheEntity e) {
        e = manager.merge(e);
        manager.flush();

        return e;
    }

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public <T> T reattach(T object) {
        return manager.merge(object);
    }
}

Все должно быть сделано в одной транзакции.

Context context = new InitialContext(your properties);
UserTransaction trans = (UserTransaction)context.lookup("java:comp/UserTransaction");
//AccessBean ab already injected;
//TheEntity e already exists

trans.begin(); //this implicates a new persistent context
e = da.reattach(e); //critical line
e.setText("New text");
e = da.updateEvent(e);
trans.commit();
TestCase.assertEquals("New text", e.getField()); //yes!

Критическая линия кажется на первый взгляд ненужной, но это не так.Если вы закомментируете эту строку, вы будете работать с сущностью, отсоединенной или присоединенной к другому постоянному контексту.Тогда вы увидите странное поведение, которое было вопросом моего вопроса.

Примечание: Нам также необходимо получить данные в явной транзакции до сих пор.

trans.begin();
e = da.reattach(e);
String s = e.getField();
trans.commit();
...