Вот пример использования контроллера, введенного Guice.
/**
* Loads a FXML file and injects its controller from the given Guice {@code Provider}
*/
public abstract class GuiceFxmlLoader {
public GuiceFxmlLoader(Stage stage, Provider<?> provider) {
mStage = Objects.requireNonNull(stage);
mProvider = Objects.requireNonNull(provider);
}
/**
* @return the FXML file name
*/
public abstract String getFileName();
/**
* Load FXML, set its controller with given {@code Provider}, and add it to {@code Stage}.
*/
public void loadView() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource(getFileName()));
loader.setControllerFactory(p -> mProvider.get());
Node view = loader.load();
setViewInStage(view);
}
catch (IOException ex) {
LOGGER.error("Failed to load FXML: " + getFileName(), ex);
}
}
private void setViewInStage(Node view) {
BorderPane pane = (BorderPane)mStage.getScene().getRoot();
pane.setCenter(view);
}
private static final Logger LOGGER = Logger.getLogger(GuiceFxmlLoader.class);
private final Stage mStage;
private final Provider<?> mProvider;
}
Вот конкретная реализация загрузчика:
public class ConcreteViewLoader extends GuiceFxmlLoader {
@Inject
public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
super(stage, provider);
}
@Override
public String getFileName() {
return "my_view.fxml";
}
}
Обратите внимание, что этот пример загружает представление в центр BoarderPane, который является корнем сцены в рабочей области. Это не относится к примеру (деталь реализации моего конкретного варианта использования), но решил оставить его, поскольку некоторые из них могут оказаться полезными.
Во-первых, некоторые пояснения к ответу KLE :
Неограниченная (допускающая значение NULL) однозначная ассоциация - единственная, которая не может быть проксирована без инструментарий байт-кода. Причина этого в том, что объект-владелец ДОЛЖЕН знать, должно ли свойство ассоциации содержать прокси-объект или NULL, и он не может определить это, просматривая столбцы своей базовой таблицы из-за взаимно однозначного сопоставления через общий PK, поэтому он в любом случае нужно с нетерпением ждать, что делает прокси бессмысленным. Вот более подробное объяснение .
ассоциации многие-к-одному (и, очевидно, один-ко-многим) не страдают от этой проблемы. Сущность-владелец может легко проверить свой собственный FK (а в случае «один ко многим» пустой прокси-сервер коллекции создается изначально и заполняется по запросу), поэтому ассоциация может быть ленивой.
Замена «один к одному» на «один ко многим» - плохая идея. Вы можете заменить его уникальным «многие к одному», но есть и другие (возможно, лучшие) варианты.
Роб Х. имеет допустимую точку, однако вы не сможете реализовать ее в зависимости от вашей модели (например, если ваша однозначная ассоциация имеет значение NULL).
Теперь, что касается исходного вопроса:
A) @ManyToOne (fetch = FetchType.LAZY)
должен работать нормально. Вы уверены, что он не перезаписывается в самом запросе? Можно указать объединенную выборку
в HQL и / или явно установить режим выборки через API критериев, который будет иметь приоритет над аннотацией класса. Если это не так, и у вас все еще есть проблемы, опубликуйте свои классы, запрос и полученный SQL для более предметного обсуждения.
B) @OneToOne
сложнее. Если он определенно не допускает значения NULL, воспользуйтесь предложением Роба Х. и укажите его как таковое:
@OneToOne(optional = false, fetch = FetchType.LAZY)
В противном случае, если вы можете изменить свою базу данных (добавить столбец внешнего ключа в таблицу владельцев), сделайте это и сопоставьте его как «объединенный ":
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()
и в OtherEntity:
@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()
Если вы не можете этого сделать (и не можете жить с нетерпеливой выборкой), инструментирование байт-кода - ваш единственный вариант. Однако я должен согласиться с CPerkins - если у вас есть 80 !!! присоединений из-за активных ассоциаций OneToOne, у вас есть более серьезные проблемы, чем это: -)
Как я объяснил в эта статья , если Вы не используете Улучшение Байт-кода , Вы не можете выбрать лениво родительскую сторону @OneToOne
ассоциация.
Однако чаще всего, Вам даже не нужна ассоциация родительской стороны, если Вы используете @MapsId
на стороне клиента:
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {
@Id
private Long id;
@Column(name = "created_on")
private Date createdOn;
@Column(name = "created_by")
private String createdBy;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Post post;
public PostDetails() {}
public PostDetails(String createdBy) {
createdOn = new Date();
this.createdBy = createdBy;
}
//Getters and setters omitted for brevity
}
С @MapsId
, id
свойство в дочерней таблице служит и Первичным ключом и Внешним ключом к родительской таблице Первичный ключ.
Так, если у Вас есть ссылка на родителя Post
объект, можно легко выбрать дочерний объект с помощью родительского идентификатора объекта:
PostDetails details = entityManager.find(
PostDetails.class,
post.getId()
);
Таким образом, Вы не будете иметь проблемы запроса N+1 , который мог быть вызван mappedBy
@OneToOne
ассоциация на родительской стороне.
Основная идея XToOnes в Hibernate заключается в том, что они в большинстве случаев не ленивы.
Одна из причин состоит в том, что когда Hibernate должен решить установить прокси (с идентификатором) или ноль,
он все равно должен заглянуть в другую таблицу , чтобы присоединиться. Стоимость доступа к другой таблице в базе данных значительна, поэтому он может также получить данные для этой таблицы в этот момент (неленивое поведение), вместо того, чтобы получать их в более позднем запросе, который потребует второго доступа к та же таблица.
Отредактировано: подробности см. в ответе ChssPly76 . Этот менее точный и подробный, ему нечего предложить. Спасибо ChssPly76.
In native Hibernate XML mappings, you can accomplish this by declaring a one-to-one mapping with the constrained attribute set to true. I am not sure what the Hibernate/JPA annotation equivalent of that is, and a quick search of the doc provided no answer, but hopefully that gives you a lead to go on.
Чтобы заставить ленивую загрузку работать с однозначными сопоставлениями, допускающими значение NULL, вам нужно разрешить hibernate выполнять инструментирование времени компиляции и добавить @LazyToOne(value = LazyToOneOption .NO_PROXY)
к отношению один к одному.
Пример сопоставления:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
@LazyToOne(value = LazyToOneOption.NO_PROXY)
public OtherEntity getOther()
Пример расширения файла Ant Build (для инструментирования времени компиляции Hibernate):
<property name="src" value="/your/src/directory"/><!-- path of the source files -->
<property name="libs" value="/your/libs/directory"/><!-- path of your libraries -->
<property name="destination" value="/your/build/directory"/><!-- path of your build directory -->
<fileset id="applibs" dir="${libs}">
<include name="hibernate3.jar" />
<!-- include any other libraries you'll need here -->
</fileset>
<target name="compile">
<javac srcdir="${src}" destdir="${destination}" debug="yes">
<classpath>
<fileset refid="applibs"/>
</classpath>
</javac>
</target>
<target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
<classpath>
<fileset refid="applibs"/>
</classpath>
</taskdef>
<instrument verbose="true">
<fileset dir="${destination}">
<!-- substitute the package where you keep your domain objs -->
<include name="/com/mycompany/domainobjects/*.class"/>
</fileset>
</instrument>
</target>