CCM NG: Tab Roles in Content Section Admin now works
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5221 8810af33-2d31-482b-a856-94f89814c4dfccm-docs
parent
ca3c5eacb4
commit
3cfb48f938
|
|
@ -29,8 +29,6 @@ import com.arsdigita.bebop.SimpleContainer;
|
||||||
import com.arsdigita.bebop.event.FormInitListener;
|
import com.arsdigita.bebop.event.FormInitListener;
|
||||||
import com.arsdigita.bebop.event.FormProcessListener;
|
import com.arsdigita.bebop.event.FormProcessListener;
|
||||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
import com.arsdigita.bebop.event.PrintEvent;
|
|
||||||
import com.arsdigita.bebop.event.PrintListener;
|
|
||||||
import com.arsdigita.bebop.form.CheckboxGroup;
|
import com.arsdigita.bebop.form.CheckboxGroup;
|
||||||
import com.arsdigita.bebop.form.Hidden;
|
import com.arsdigita.bebop.form.Hidden;
|
||||||
import com.arsdigita.bebop.form.Option;
|
import com.arsdigita.bebop.form.Option;
|
||||||
|
|
@ -39,23 +37,20 @@ import com.arsdigita.bebop.form.Submit;
|
||||||
import com.arsdigita.bebop.form.Widget;
|
import com.arsdigita.bebop.form.Widget;
|
||||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||||
import com.arsdigita.globalization.GlobalizedMessage;
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
import com.arsdigita.ui.admin.GlobalizationUtil;
|
|
||||||
import com.arsdigita.util.UncheckedWrapperException;
|
|
||||||
import com.arsdigita.xml.Element;
|
import com.arsdigita.xml.Element;
|
||||||
|
|
||||||
|
import org.libreccm.core.UnexpectedErrorException;
|
||||||
import org.libreccm.security.Party;
|
import org.libreccm.security.Party;
|
||||||
import org.librecms.CmsConstants;
|
import org.librecms.CmsConstants;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TooManyListenersException;
|
import java.util.TooManyListenersException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form for adding multiple parties to a role.
|
* Form for adding multiple parties to a role.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:yannick.buelter@yabue.de">Yannick Bülter</a>
|
* @author <a href="mailto:yannick.buelter@yabue.de">Yannick Bülter</a>
|
||||||
* @author Scott Seago (scott@arsdigita.com)
|
* @author Scott Seago (scott@arsdigita.com)
|
||||||
* @version Id: PartyAddForm.java 754 2005-09-02 13:26:17Z sskracic $
|
|
||||||
*/
|
*/
|
||||||
public abstract class PartyAddForm extends SimpleContainer
|
public abstract class PartyAddForm extends SimpleContainer
|
||||||
implements FormInitListener, FormProcessListener {
|
implements FormInitListener, FormProcessListener {
|
||||||
|
|
@ -64,118 +59,129 @@ public abstract class PartyAddForm extends SimpleContainer
|
||||||
private final static String PARTIES = "parties";
|
private final static String PARTIES = "parties";
|
||||||
private final static String SUBMIT = "addSubmit";
|
private final static String SUBMIT = "addSubmit";
|
||||||
private final static String CANCEL = "addCancel";
|
private final static String CANCEL = "addCancel";
|
||||||
private final static String SUBMIT_LABEL = "Add Members";
|
|
||||||
private final static String CANCEL_LABEL = "Cancel";
|
|
||||||
|
|
||||||
private Widget m_search;
|
private Widget searchWidget;
|
||||||
private RequestLocal m_query;
|
private RequestLocal queryRequestLocal;
|
||||||
|
|
||||||
private CMSContainer m_noMatches;
|
private CMSContainer noMatchesContainer;
|
||||||
private CMSContainer m_matches;
|
private CMSContainer matchesContainer;
|
||||||
|
|
||||||
private Form m_form;
|
|
||||||
private Hidden m_searchQuery;
|
|
||||||
private Submit m_cancel;
|
|
||||||
|
|
||||||
|
private Form form;
|
||||||
|
private Hidden searchQueryField;
|
||||||
|
private Submit cancelButton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private access prevents this constructor from ever being called
|
* Private access prevents this constructor from ever being called directly.
|
||||||
* directly.
|
|
||||||
*/
|
*/
|
||||||
private PartyAddForm() {
|
private PartyAddForm() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param search The widget on the search form that contains the value
|
* @param searchWidget The widget on the search form that contains the value
|
||||||
* of the search string.
|
* of the search string.
|
||||||
*/
|
*/
|
||||||
public PartyAddForm(Widget search) {
|
public PartyAddForm(final Widget searchWidget) {
|
||||||
|
|
||||||
this();
|
this();
|
||||||
|
|
||||||
m_search = search;
|
this.searchWidget = searchWidget;
|
||||||
|
|
||||||
m_query = new RequestLocal() {
|
queryRequestLocal = new RequestLocal() {
|
||||||
protected Object initialValue(PageState state) {
|
|
||||||
return makeQuery(state);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
m_form = makeForm();
|
@Override
|
||||||
|
protected Object initialValue(final PageState state) {
|
||||||
|
return makeQuery(state);
|
||||||
|
}
|
||||||
|
|
||||||
Label title = new Label(GlobalizationUtil.globalize("cms.ui.matches"));
|
};
|
||||||
|
|
||||||
|
form = makeForm();
|
||||||
|
|
||||||
|
final Label title = new Label(new GlobalizedMessage("cms.ui.matches",
|
||||||
|
CmsConstants.CMS_BUNDLE));
|
||||||
title.setFontWeight(Label.BOLD);
|
title.setFontWeight(Label.BOLD);
|
||||||
|
|
||||||
Label label = new Label(GlobalizationUtil.globalize("cms.ui.there_was_no_one_matching_the_search_criteria"));
|
final Label label = new Label(new GlobalizedMessage(
|
||||||
|
"cms.ui.there_was_no_one_matching_the_search_criteria",
|
||||||
|
CmsConstants.CMS_BUNDLE));
|
||||||
label.setFontWeight("em");
|
label.setFontWeight("em");
|
||||||
|
|
||||||
m_noMatches = new CMSContainer();
|
noMatchesContainer = new CMSContainer();
|
||||||
m_noMatches.add(title);
|
noMatchesContainer.add(title);
|
||||||
m_noMatches.add(label);
|
noMatchesContainer.add(label);
|
||||||
add(m_noMatches);
|
super.add(noMatchesContainer);
|
||||||
|
|
||||||
m_matches = new CMSContainer();
|
matchesContainer = new CMSContainer();
|
||||||
m_matches.add(title);
|
matchesContainer.add(title);
|
||||||
m_matches.add(m_form);
|
matchesContainer.add(form);
|
||||||
add(m_matches);
|
super.add(matchesContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the form used to add parties.
|
* Build the form used to add parties.
|
||||||
*
|
*
|
||||||
* @return The form
|
* @return The form
|
||||||
*/
|
*/
|
||||||
private Form makeForm() {
|
private Form makeForm() {
|
||||||
final CMSForm form = new CMSForm("AddParties") {
|
|
||||||
@Override
|
final CMSForm addPartyForm = new CMSForm("AddParties") {
|
||||||
public final boolean isCancelled(final PageState state) {
|
|
||||||
return m_cancel.isSelected(state);
|
@Override
|
||||||
}
|
public final boolean isCancelled(final PageState state) {
|
||||||
};
|
return cancelButton.isSelected(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// This hidden field will store the search query. A hidden widget is
|
// This hidden field will store the search query. A hidden widget is
|
||||||
// used instead of a request local variable because the search query
|
// used instead of a request local variable because the search query
|
||||||
// should only be updated when the search form is submitted.
|
// should only be updated when the search form is submitted.
|
||||||
m_searchQuery = new Hidden(SEARCH_QUERY);
|
searchQueryField = new Hidden(SEARCH_QUERY);
|
||||||
form.add(m_searchQuery, ColumnPanel.FULL_WIDTH);
|
addPartyForm.add(searchQueryField, ColumnPanel.FULL_WIDTH);
|
||||||
|
|
||||||
Label l = new Label(
|
final Label hintLabel = new Label(
|
||||||
new GlobalizedMessage("Check the box next to the name of the person(s) to assign to this role."));
|
new GlobalizedMessage("cms.ui.party_add_form.hint",
|
||||||
form.add(l, ColumnPanel.FULL_WIDTH);
|
CmsConstants.CMS_BUNDLE));
|
||||||
|
addPartyForm.add(hintLabel, ColumnPanel.FULL_WIDTH);
|
||||||
|
|
||||||
// Add the list of parties that can be added.
|
// Add the list of parties that can be added.
|
||||||
CheckboxGroup m_parties = new CheckboxGroup(PARTIES);
|
final CheckboxGroup partyCheckboxes = new CheckboxGroup(PARTIES);
|
||||||
m_parties.addValidationListener(new NotNullValidationListener());
|
partyCheckboxes.addValidationListener(new NotNullValidationListener());
|
||||||
try {
|
try {
|
||||||
m_parties.addPrintListener(event -> {
|
partyCheckboxes.addPrintListener(event -> {
|
||||||
CheckboxGroup target = (CheckboxGroup) event.getTarget();
|
final CheckboxGroup target = (CheckboxGroup) event.getTarget();
|
||||||
PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
// Ensures that the init listener gets fired before the
|
// Ensures that the init listener gets fired before the
|
||||||
// print listeners.
|
// print listeners.
|
||||||
FormData data = m_form.getFormData(state);
|
final FormData data = addPartyForm.getFormData(state);
|
||||||
addParties(state, target);
|
addParties(state, target);
|
||||||
});
|
});
|
||||||
} catch (TooManyListenersException e) {
|
} catch (TooManyListenersException ex) {
|
||||||
UncheckedWrapperException.throwLoggedException(getClass(), "Too many listeners", e);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
form.add(m_parties, ColumnPanel.FULL_WIDTH);
|
addPartyForm.add(partyCheckboxes, ColumnPanel.FULL_WIDTH);
|
||||||
|
|
||||||
// Submit and Cancel buttons.
|
// Submit and Cancel buttons.
|
||||||
SimpleContainer s = new SimpleContainer();
|
final SimpleContainer buttonContainer = new SimpleContainer();
|
||||||
Submit m_submit = new Submit(SUBMIT, new GlobalizedMessage(SUBMIT_LABEL, CmsConstants.CMS_BUNDLE));
|
final Submit submitButton = new Submit(SUBMIT,
|
||||||
s.add(m_submit);
|
new GlobalizedMessage(
|
||||||
m_cancel = new Submit(CANCEL, new GlobalizedMessage(CANCEL_LABEL, CmsConstants.CMS_BUNDLE));
|
"cms.ui.save",
|
||||||
s.add(m_cancel);
|
CmsConstants.CMS_BUNDLE));
|
||||||
form.add(s, ColumnPanel.FULL_WIDTH | ColumnPanel.CENTER);
|
buttonContainer.add(submitButton);
|
||||||
|
cancelButton = new Submit(CANCEL,
|
||||||
|
new GlobalizedMessage("cms.ui.cancel",
|
||||||
|
CmsConstants.CMS_BUNDLE));
|
||||||
|
buttonContainer.add(cancelButton);
|
||||||
|
addPartyForm.add(buttonContainer, ColumnPanel.FULL_WIDTH
|
||||||
|
| ColumnPanel.CENTER);
|
||||||
|
|
||||||
form.addInitListener(this);
|
addPartyForm.addInitListener(this);
|
||||||
form.addProcessListener(this);
|
addPartyForm.addProcessListener(this);
|
||||||
|
|
||||||
return form;
|
return addPartyForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,7 +190,7 @@ public abstract class PartyAddForm extends SimpleContainer
|
||||||
* @return The "add party" form
|
* @return The "add party" form
|
||||||
*/
|
*/
|
||||||
public Form getForm() {
|
public Form getForm() {
|
||||||
return m_form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -193,88 +199,96 @@ public abstract class PartyAddForm extends SimpleContainer
|
||||||
* @return The widget that contains the search string
|
* @return The widget that contains the search string
|
||||||
*/
|
*/
|
||||||
protected Widget getSearchWidget() {
|
protected Widget getSearchWidget() {
|
||||||
return m_searchQuery;
|
return searchQueryField;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the form is cancelled, false otherwise.
|
* Return true if the form is cancelled, false otherwise.
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
|
*
|
||||||
* @return true if the form is cancelled, false otherwise.
|
* @return true if the form is cancelled, false otherwise.
|
||||||
|
*
|
||||||
* @pre ( state != null )
|
* @pre ( state != null )
|
||||||
*/
|
*/
|
||||||
public boolean isCancelled(PageState state) {
|
public boolean isCancelled(final PageState state) {
|
||||||
return m_cancel.isSelected(state);
|
return cancelButton.isSelected(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds parties to the option group.
|
* Adds parties to the option group.
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param target The option group
|
* @param target The option group
|
||||||
|
*
|
||||||
* @pre ( state != null && target != null )
|
* @pre ( state != null && target != null )
|
||||||
*/
|
*/
|
||||||
private void addParties(PageState state, OptionGroup target) {
|
private void addParties(final PageState state, final OptionGroup target) {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Party> parties = (List<Party>) m_query.get(state);
|
final List<Party> parties = (List<Party>) queryRequestLocal.get(state);
|
||||||
|
|
||||||
|
target.clearOptions();
|
||||||
|
|
||||||
for (final Party party : parties) {
|
for (final Party party : parties) {
|
||||||
target.addOption(new Option(
|
target.addOption(new Option(
|
||||||
Long.toString(party.getPartyId()),
|
Long.toString(party.getPartyId()),
|
||||||
new Label(new GlobalizedMessage(party.getName()))
|
new Label(new GlobalizedMessage(party.getName()))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a {@link Object} that encapsulates
|
* Generates a {@link Object} that encapsulates search results.
|
||||||
* search results.
|
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
protected abstract List<Party> makeQuery(PageState state);
|
protected abstract List<Party> makeQuery(PageState state);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the search query in the hidden field.
|
* Stores the search query in the hidden field.
|
||||||
*
|
*
|
||||||
* @param event The form event
|
* @param event The form event
|
||||||
|
*
|
||||||
|
* @throws com.arsdigita.bebop.FormProcessException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(FormSectionEvent event) throws FormProcessException {
|
public void init(final FormSectionEvent event) throws FormProcessException {
|
||||||
|
|
||||||
PageState state = event.getPageState();
|
PageState state = event.getPageState();
|
||||||
|
|
||||||
m_searchQuery.setValue(state, m_search.getValue(state));
|
searchQueryField.setValue(state, searchWidget.getValue(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process listener for the "Add parties" form.
|
* Process listener for the "Add parties" form.
|
||||||
*
|
*
|
||||||
* @param event The form event
|
* @param event The form event
|
||||||
|
*
|
||||||
|
* @throws com.arsdigita.bebop.FormProcessException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public abstract void process(FormSectionEvent event)
|
public abstract void process(FormSectionEvent event)
|
||||||
throws FormProcessException;
|
throws FormProcessException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the appropriate frame.
|
* Displays the appropriate frame.
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param parent The parent DOM element
|
* @param parent The parent DOM element
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void generateXML(PageState state, Element parent) {
|
public void generateXML(final PageState state, final Element parent) {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Party> searchResults = (List<Party>) m_query.get(state);
|
final List<Party> searchResults = (List<Party>) queryRequestLocal.get(state);
|
||||||
|
|
||||||
if ( searchResults.size() > 0 ) {
|
if (searchResults.size() > 0) {
|
||||||
m_matches.generateXML(state, parent);
|
matchesContainer.generateXML(state, parent);
|
||||||
} else {
|
} else {
|
||||||
m_noMatches.generateXML(state, parent);
|
noMatchesContainer.generateXML(state, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,24 +33,23 @@ import com.arsdigita.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class PartySearchForm extends BaseForm {
|
public class PartySearchForm extends BaseForm {
|
||||||
|
|
||||||
private final static String SEARCH_LABEL = "Search";
|
private final TextField searchField;
|
||||||
|
|
||||||
private final TextField m_search;
|
|
||||||
|
|
||||||
public PartySearchForm() {
|
public PartySearchForm() {
|
||||||
super("SearchParties", gz("cms.ui.search"));
|
super("SearchParties", gz("cms.ui.search"));
|
||||||
|
|
||||||
addComponent(new Label(gz("cms.ui.search_prompt")));
|
addComponent(new Label(gz("cms.ui.search_prompt")));
|
||||||
|
|
||||||
m_search = new TextField(new StringParameter("query"));
|
searchField = new TextField(new StringParameter("query"));
|
||||||
m_search.setSize(40);
|
searchField.setSize(40);
|
||||||
addComponent(m_search);
|
addComponent(searchField);
|
||||||
|
|
||||||
addAction(new Submit("finish", gz("cms.ui.search")));
|
addAction(new Submit("finish", gz("cms.ui.search")));
|
||||||
addAction(new Cancel());
|
addAction(new Cancel());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final void register(final Page page) {
|
public final void register(final Page page) {
|
||||||
super.register(page);
|
super.register(page);
|
||||||
|
|
||||||
|
|
@ -58,6 +57,6 @@ public class PartySearchForm extends BaseForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextField getSearchWidget() {
|
public TextField getSearchWidget() {
|
||||||
return m_search;
|
return searchField;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,7 @@ public class RoleAdminPaneController {
|
||||||
"No ContentSection with ID %d in the database."
|
"No ContentSection with ID %d in the database."
|
||||||
+ "Where did that ID come from?",
|
+ "Where did that ID come from?",
|
||||||
CMS.getContext().getContentSection().getObjectId())));
|
CMS.getContext().getContentSection().getObjectId())));
|
||||||
|
sectionManager.addRoleToContentSection(role, contentSection);
|
||||||
final Folder rootDocumentsFolder = contentSection
|
final Folder rootDocumentsFolder = contentSection
|
||||||
.getRootDocumentsFolder();
|
.getRootDocumentsFolder();
|
||||||
final Folder rootAssetsFolder = contentSection.getRootAssetsFolder();
|
final Folder rootAssetsFolder = contentSection.getRootAssetsFolder();
|
||||||
|
|
|
||||||
|
|
@ -510,3 +510,7 @@ cms.ui.category.is_visible=Visible?
|
||||||
cms.ui.category.move=Move category
|
cms.ui.category.move=Move category
|
||||||
cms.ui.title=Title
|
cms.ui.title=Title
|
||||||
cms.ui.select_one=Choose one
|
cms.ui.select_one=Choose one
|
||||||
|
cms.ui.search_prompt=Search to add new members
|
||||||
|
cms.ui.matches=Matches
|
||||||
|
cms.ui.there_was_no_one_matching_the_search_criteria=There not no one matching the search criteria
|
||||||
|
cms.ui.party_add_form.hint=Check the box next to the name of the person(s) to assign to this role.
|
||||||
|
|
|
||||||
|
|
@ -507,3 +507,7 @@ cms.ui.category.is_visible=Sichtbar?
|
||||||
cms.ui.category.move=Kategorie verschieben
|
cms.ui.category.move=Kategorie verschieben
|
||||||
cms.ui.title=Titel
|
cms.ui.title=Titel
|
||||||
cms.ui.select_one=Bitte ausw\u00e4hlen
|
cms.ui.select_one=Bitte ausw\u00e4hlen
|
||||||
|
cms.ui.search_prompt=Suche um neue Mitglieder zu erg\u00e4nzen
|
||||||
|
cms.ui.matches=Treffer
|
||||||
|
cms.ui.there_was_no_one_matching_the_search_criteria=Keine Element erf\u00fcllt die Suchkritieren
|
||||||
|
cms.ui.party_add_form.hint=Aktivieren Sie die Checkbox vor dem Namen, um die Person oder Gruppe der Rolle hinzuzuf\u00fcgen
|
||||||
|
|
|
||||||
|
|
@ -469,3 +469,7 @@ cms.ui.category.linked_none=No linked categories
|
||||||
cms.ui.category.move=Move category
|
cms.ui.category.move=Move category
|
||||||
cms.ui.title=Title
|
cms.ui.title=Title
|
||||||
cms.ui.select_one=Choose one
|
cms.ui.select_one=Choose one
|
||||||
|
cms.ui.search_prompt=Search to add new members
|
||||||
|
cms.ui.matches=Matches
|
||||||
|
cms.ui.there_was_no_one_matching_the_search_criteria=There not no one matching the search criteria
|
||||||
|
cms.ui.party_add_form.hint=Check the box next to the name of the person(s) to assign to this role.
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import javax.persistence.EntityManager;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
import javax.persistence.criteria.JoinType;
|
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue