I implemented a workbench permission system with groups and permissions.
A reference table workbench_group_permissions_reference has references so I can easily add and remove permissions to a group.
Adding a new reference entry works fine, but removing does not. I do not get any error, but the reference still exists in the database after removal. I am using postgreSQL.
Here is my reference class:
#XmlRootElement
#Entity
#Table(name = "workbench_group_permissions_reference", uniqueConstraints = {
#UniqueConstraint(columnNames = { "workbenchgroupspermissions_id", "workbench_groups_id" }) })
public class WorkbenchGroupPermissionReferenceEntity extends BasicEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToOne
#JoinColumn(name = "workbenchgroupspermissions_id")
private WorkbenchPermissionEntity workbenchPermission;
#ManyToOne
#JoinColumn(name = "workbench_groups_id")
private WorkbenchGroupEntity workbenchGroup;
/**
* Empty constructor to make JPA happy.
*/
public WorkbenchGroupPermissionReferenceEntity() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public WorkbenchPermissionEntity getWorkbenchPermission() {
return workbenchPermission;
}
public void setWorkbenchPermission(WorkbenchPermissionEntity workbenchPermission) {
this.workbenchPermission = workbenchPermission;
}
public WorkbenchGroupEntity getWorkbenchGroup() {
return workbenchGroup;
}
public void setWorkbenchGroup(WorkbenchGroupEntity workbenchGroup) {
this.workbenchGroup = workbenchGroup;
}
}
This is my remove method:
public void deleteWorkbenchGroupPermission(final WorkbenchGroupPermissionReferenceEntity workbenchGroupPermission) {
long id = workbenchGroupPermission.getId();
super.delete(WorkbenchGroupPermissionReferenceEntity.class, id);
}
And the super.delete method:
protected void delete(final Class<?> type, final Object id) {
Object ref = this.em.getReference(type, id);
this.em.remove(ref);
}
What am I missing here?
The link in the comment of Dragan was pointing me to the right direction.
I tried to delete the reference, but the owning entity (WorkbenchGroupEntity) still had the reference.
What I did to solve the problem was to first remove the reference from the owning entity and then remove the cross-reference entity afterwards:
WorkbenchGroupPermissionReferenceEntity permissionToRemove = new WorkbenchGroupPermissionReferenceEntity();
for(WorkbenchGroupPermissionReferenceEntity permissionReference : existingGroupPermissions) {
Long permissionRefernceId = permissionReference.getId();
if(permissionRefernceId.equals(permissionId)){
permissionToRemove = permissionReference;
} else {
newGroupPermissions.add(permissionReference);
}
}
workbenchGroupEntity.setWorkbenchGroupPermissions(newGroupPermissions);
workbenchGroupControl.updateWorkbenchGroup(workbenchGroupEntity);
workbenchGroupPermissionsControl.deleteWorkbenchGroupPermission(permissionToRemove);
EDIT:
As the solution mentioned above was the main reason for the delete not working properly, I made another stupid mistake: I was comparing the id of the cross reference entity to the id of the permission id instead of the permission id itself, so the reference was never found.
Updated check:
for (WorkbenchGroupPermissionReferenceEntity permissionReference : existingGroupPermissions) {
// here was the mistake
Long permissionReferenceId = permissionReference.getWorkbenchPermission().getId();
if (permissionReferenceId.equals(permissionId)) {
permissionToRemove = permissionReference;
} else {
newGroupPermissions.add(permissionReference);
}
}
Related
I am trying to use JPA to fetch records from database. However I am able to insert records indatabse and even get all the records using createQuery method of class EntityManager.
But in below case I am not getting why the condition in where clause is not working.
Please help me figure it out.
POJO class :
#Entity
#Table(name = "frameworks_filter")
public class FilteredFrameworksDbStructure {
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "regular_name")
private String regularName;
#Column(name = "component_name")
private String componentName;
#Column(name = "component_owner")
private String componentOwner;
#Column(name = "frameworks")
private String frameworks;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRegularName() {
return regularName;
}
public void setRegularName(String regularName) {
this.regularName = regularName;
}
public String getComponentName() {
return componentName;
}
public void setComponentName(String componentName) {
this.componentName = componentName;
}
public String getComponentOwner() {
return componentOwner;
}
public void setComponentOwner(String componentOwner) {
this.componentOwner = componentOwner;
}
public String getFrameworks() {
return frameworks;
}
public void setFrameworks(String frameworks) {
this.frameworks = frameworks;
}
}
DAO class method:
public List<FilteredFrameworksDbStructure> getFilteredFrameworks(String regularName) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
List<FilteredFrameworksDbStructure> filteredFrameworksDbStructureList = entityManager
.createQuery("from FilteredFrameworksDbStructure F where F.regularName = :regular", FilteredFrameworksDbStructure.class)
.setParameter("regular", regularName)
.getResultList();
return filteredFrameworksDbStructureList;
}
Issue : Condition in where clause does not work. It simply fetch all the records irrespective of the regularName provided.
Regards,
Parag Vinchurkar
Why don't you use the JpaRepository or CrudRepository to fetch your results? Check out this tutorial here and here on how to use them.
And you can use your where clause. Please see below the example repository you can use to obtain the same results as the entityManager
public interface FilteredFrameworksDbStructureRepo extends JpaRepository<FilteredFrameworksDbStructure , Integer>{
List<FilteredFrameworksDbStructure> findAllByRegularName(String regularName)
}
Please note that you will have to change your id member variable from int to Integer
Well, I'm using Hibernate for the first time and, unexpectedly, it works. Except for one thing: an insert with a pk already inserted overwrite the record instaed of preventing it.
That's my simple code:
#Controller
public class SimpleController {
#Autowired
UserRepository userRepository;
#GetMapping("/mainPage")
public String viewMainPage(){
return "mainPage";
}
#GetMapping("/nuovo-utente")
public String viewInserisciUtente(Model model){
model.addAttribute("nuovoUtente", new Utente());
return "nuovo-utente";
}
#PostMapping("/nuovo-utente")
public String memorizzaUtente(#ModelAttribute Utente utente){
userRepository.save(utente);
return "output";
}
}
#Entity
public class Utente {
#Id
private int id;
private String citta=null;
private String genere=null;
private String data_nascita=null;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCitta() {
return citta;
}
public void setCitta(String citta) {
this.citta = citta;
}
public String getGenere() {
return genere;
}
public void setGenere(String genere) {
this.genere = genere;
}
public String getData_nascita() {
return data_nascita;
}
public void setData_nascita(String data_nascita) {
this.data_nascita = data_nascita;
}
}
Any help will be appreciated.
EDIT: I've added the entity class to help you understanding my problem. Hoping that this will help.
Thanks you all
If you look at CrudRepository documentation, then we don't have update method, but we only have save method, which is used to add or update existing records.
In your case, you might have updated an entity (except its Id field) and tried saving the entity. So, CrudRepository will update the existing value for given Id, since it is already present.
Try adding ID generation strategy to id field.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
I'm currently working on a project where I'm trying to get a list of enities from table which does not have a primary key (dk_systemtherapie_merkmale). This table is 1:n related to another table (dk_systemtherapie). See the screenshot for the table structure.
When getting an entry for dk_systemtherapie, the program fetches the Collection "dkSystemtherapieMerkmalesById". However, the first table entry is fetched as often as the number of actual entries in the table is. It never fetches the other entries from dk_systemtherapie_merkmale. I assume it has something to do with the fact that hibernate can't differ between the entries, but I don't know how to fix it.
Table schema
I've created two corresponding entity classes, dk_systemtherapie:
#Entity
#Table(name = "dk_systemtherapie", schema = "***", catalog = "")
public class DkSystemtherapieEntity {
private int id;
private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById;
#Id
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(mappedBy = "dkSystemtherapieByEintragId")
public Collection<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmalesById() {
return dkSystemtherapieMerkmalesById;
}
public void setDkSystemtherapieMerkmalesById(Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById) {
this.dkSystemtherapieMerkmalesById = dkSystemtherapieMerkmalesById;
}
}
Here the second one, which is accessing the table without a primary key, dk_systhemtherapie_merkmale:
#Entity #IdClass(DkSystemtherapieMerkmaleEntity.class)
#Table(name = "dk_systemtherapie_merkmale", schema = "***", catalog = "")
public class DkSystemtherapieMerkmaleEntity implements Serializable {
#Id private Integer eintragId;
#Id private String feldname;
#Id private String feldwert;
private DkSystemtherapieEntity dkSystemtherapieByEintragId;
#Basic
#Column(name = "eintrag_id")
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
#Basic
#Column(name = "feldname")
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
#Basic
#Column(name = "feldwert")
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
public void setDkSystemtherapieByEintragId(DkSystemtherapieEntity dkSystemtherapieByEintragId) {
this.dkSystemtherapieByEintragId = dkSystemtherapieByEintragId;
}
}
I assume the problem is releated to the fact that Hibernate is using the following annotation as the one and only id for fetching data from database.
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
This leads to the problem that when getting more than one entry with the same id (as the id is not unique), you will get the number of entries you would like to but hibernate is always fetching the first entry for this id. So in fact you are getting dublicate entries.
So how to fix this?
According to this question: Hibernate and no PK, there are two workarounds which are actually only working when you don't have NULL entries in your table (otherwise the returning object will be NULL as well) and no 1:n relationship. For my understanding, hibernate is not supporting entities on tables without primary key (documentation). To make sure getting the correct results, I would suggest using NativeQuery.
Remove the Annotations and private DkSystemtherapieEntity dkSystemtherapieByEintragId; (incl. beans) from DkSystemtherapieMerkmaleEntity.java und add a constructor.
public class DkSystemtherapieMerkmaleEntity {
private Integer eintragId;
private String feldname;
private String feldwert;
public DkSystemtherapieMerkmaleEntity(Integer eintragId, String feldname, String feldwert) {
this.eintragId = eintragId;
this.feldname = feldname;
this.feldwert = feldwert;
}
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
}
Remove private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById; (incl. beans) from DkSystemtherapieEntity.java.
Always when you need to get entries for a particular eintrag_id, use the following method instead of the Collection in DkSystemtherapieEntity.java.
public List<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmaleEntities(int id) {
Transaction tx = session.beginTransaction();
String sql = "SELECT * FROM dk_systemtherapie_merkmale WHERE eintrag_id =:id";
List<Object[]> resultList;
resultList = session.createNativeQuery(sql)
.addScalar("eintrag_id", IntegerType.INSTANCE)
.addScalar("feldname", StringType.INSTANCE)
.addScalar("feldwert", StringType.INSTANCE)
.setParameter("id", id).getResultList();
tx.commit();
List<DkSystemtherapieMerkmaleEntity> merkmale = new ArrayList<>();
for (Object[] o : resultList) {
merkmale.add(new DkSystemtherapieMerkmaleEntity((Integer) o[0], (String) o[1], (String) o[2]));
}
return merkmale;
}
Call getDkSystemtherapieMerkmaleEntities(dkSystemtherapieEntityObject.getid()) instead of getDkSystemtherapieMerkmalesById().
Below is the DAO. I am getting the first UppeningUsers object. Note that here for this function I do not want to return peopleWhoBlockedMe set which is located inside the UppeningUsers..
But in different functions I would like to return that information. Note that Both of them are LAZY fetching. With evict I tried to detach the object but still it did not work.
First of all RESTcontroller is below. Then the DAO code is below. Then two entity descriptions are below.
Question is: I see that until
return new ResponseEntity(returned, HttpStatus.OK);
There is only one query which is the typical select. I do not want hibernate to go and take also UserBlock information of that specific UppeningUser. Because it is not needed for this service response. However even though it is lazy loading for some reason
return new ResponseEntity(returned, HttpStatus.OK);
calls the hibernate. I dont know why in restcontroller still it is connected to the database. I tried evict but didnt work.
The json response is
{"id":7,"peopleWhoBlockedMe":[{"blockedId":7}]}
But I do not want for this function to return this peopleWhoBlockedMe. It can be empty.
PLEASE NOTE that in other service for example I will explictly request this peopleWhoBlockedMe but just for this business logic I do not need this information. So what I can do to prevent this so whenever I actually want to call peopleWhoBlockedMe I can get it. Not automaticly.
#RestController
public class TempController {
#Autowired
UppeningUsersService uppeningUsersService;
#RequestMapping(value = "/testing", method = RequestMethod.GET)
public ResponseEntity<UppeningUsers> getPhotos() {
try {
UppeningUsers returned = uppeningUsersService.getUsersDetailsPartial();
return new ResponseEntity<UppeningUsers>(returned, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
This part is the DAO.
#Repository
public class UppeningUsersDAO {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf) {
this.sessionFactory = sf;
}
/**
* Get Existing user. Return error if there is not.
* #param incomingUser user who requested access.
* #return returns the guy information. All information.
*/
#Transactional
public UppeningUsers getUserDetails() throws Exception {
Session session = this.sessionFactory.getCurrentSession();
Query query = session.createQuery("from UppeningUsers ");
UppeningUsers returning = (UppeningUsers) query.list().get(0);
session.evict(returning);
return returning;
}
}
The main table is this one..
#Entity
#Table(name = "uppening_users")
#Proxy(lazy = true)
public class UppeningUsers {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private
int id;
#OneToMany(mappedBy = "blockedId",cascade =CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserBlocks> peopleWhoBlockedMe;
public UppeningUsers() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<UserBlocks> getPeopleWhoBlockedMe() {
return peopleWhoBlockedMe;
}
public void setPeopleWhoBlockedMe(Set<UserBlocks> peopleWhoBlockedMes) {
this.peopleWhoBlockedMe = peopleWhoBlockedMes;
}
}
Now here is the other table.
#Entity
#Table(name="user_blocks")
#Proxy(lazy = true)
public class UserBlocks {
#Id
#Column(name="id")
#GeneratedValue(strategy= GenerationType.IDENTITY)
int id;
#Column(name = "blocked_id",insertable = false,updatable = false)
private int blockedId;
public int getBlockedId() {
return blockedId;
}
public void setBlockedId(int blockedId) {
this.blockedId = blockedId;
}
}
UPDATE: 2 forgot to add the service
#Service("uppeningUserService")
public class UppeningUsersService {
#Autowired
UppeningUsersDAO uppeningUsersDAO;
public UppeningUsers getUsersDetailsPartial( ) throws Exception {
return uppeningUsersDAO.getUserDetails();
}
}
Jens is right about her sentence. The layer methodology and writing business objects fix the issue. Thank you.
I have configured the OneToMany mappings for my tables.So when inserting values to the fisrt table on second time it gives me an error Cannot insert duplicate key row in object. Here is my tables.
Table -1 (feature_id is pk and auto generated by table) and name is inserting by me.
Feature_id(PK)
Name
feature table has index
"GO
CREATE UNIQUE INDEX idx_Name ON "dbo"."Feature"(Name)
Table-2 (Feature_Version_id PK and auto generated by table)
Feature_Version_id ,
Version_Name
Feature_id
POJO classes are :
#Entity
#Table(name="FEATURE")
public class Feature {
private int feature_id;
private String name;
private Set<FeatureVersion> featureversion = new HashSet<FeatureVersion>(0);
public Feature() {
}
public Feature(String name ,Set<FeatureVersion> featureversion) {
this.name = name;
this.featureversion = featureversion;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="FEATURE_ID")
public int getFeature_id() {
return feature_id;
}
public void setFeature_id(int feature_id) {
this.feature_id = feature_id;
}
#Column(name="NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(fetch=FetchType.LAZY,mappedBy="feature")
public Set<FeatureVersion> getFeatureversion() {
return featureversion;
}
public void setFeatureversion(Set<FeatureVersion> featureversion) {
this.featureversion = featureversion;
}
}
Second table POJO class:
#Entity
#Table(name="FEATURE_VERSION")
public class FeatureVersion {
private int feature_version_id;
private String version_name;
private int feature_id;
private Feature feature;
private Set<PartFeatureVersion> partfeatureversion = new HashSet<PartFeatureVersion>(0);
public FeatureVersion() {
}
public FeatureVersion(Feature feature, String version_name, int feature_id) {
this.feature = feature;
this.version_name = version_name;
this.feature_id = feature_id;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="FEATURE_VERSION_ID")
public int getFeature_version_id() {
return feature_version_id;
}
public void setFeature_version_id(int feature_version_id) {
this.feature_version_id = feature_version_id;
}
#Column(name="VERSION_NAME")
public String getVersion_name() {
return version_name;
}
public void setVersion_name(String version_name) {
this.version_name = version_name;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="feature_id")
public Feature getFeature() {
return feature;
}
public void setFeature(Feature feature) {
this.feature = feature;
}
#OneToMany(fetch=FetchType.LAZY,mappedBy="featureversion")
public Set<PartFeatureVersion> getPartfeatureversion() {
return partfeatureversion;
}
public void setPartfeatureversion(Set<PartFeatureVersion> partfeatureversion) {
this.partfeatureversion = partfeatureversion;
}
}
Main class :
Session session = (Session) HibernateUtil.getSessionFactory().openSession();
Feature feature = new Feature();
FeatureVersion featurever = new FeatureVersion();
feature.setName("stack");
session.save(feature);
featurever.setVersion_name("12.2");
featurever.setFeature(feature);
feature.getFeatureversion().add(featurever);
session.save(featurever);
session.getTransaction().commit();
session.flush();
Here is my input values :
(feature id generated by table)
First attempt for first table: stack
First attempt for second table : 12.2
(feature_id come from feature table)
second attempt for first table: stack
second attempt for second table : 12.3
OneToMany configuration will take care if more than one values come to OneToMany releationship ? Or i need to check if value is exist then just the version name ? These all values loop through from the list. Please advise what should i do here .
Thanks,