we havent used JPA or any other ORM tools in our web application, now we have been on updating whole stuff to Java EE 6,
my problem about is JPA
,i have been looking for an answer,and learn how people solve that kinda issue,
i have 2 entites,
#Entity Person
{
#Id
private long id;
#JoinColumn(name="CITY_ID")
#OneToOne(fetch=FetchType.LAZY)
private City city;
....
}
and my second entity
#Entity City
{
#Id
private long id;
private String name;
.....
}
i am querying person entity and i show one on my jsf page
i have 2 input fields for Person.city to show on my jsf page
inputhidden for id and inputtext for name
people are selecting cities from a popup then
i set hidden component for city id, with new selected new value,
and the same for name,
everthing goes fine till now,
when i merge Person Entity, it tries to merge City also, but with an id already defined on table, so constraint error for Cirty Id.
what are you doing for this kinda problem?
i thought valueChange action for inputHidden,but at jsf Life cycle it happens before update model so even if i replace Person.City entity with new one in action ,
it will updated again (actually with the same values but it will be done twice)
,So what is the best workaround for this situation?
thanx
You are trying to save a new Person and assign it to an existing City? If so, and if you are using PersistantManager.persist(person) than it tries to create a new City, which fails. You can tell the relationship from Person to City what options to follow, see Cascading (MERGE in your case i guess).
Seam Faces ,converter as it explains in here u need special id to entity converter,
that was my problem
Related
I have a join table with an extra column for a many-to-many relation between Users and Projects. It looks like this:
user_id (pk)
project_id (pk)
role (pk)
1
1
MANAGER
2
1
WORKER
1
2
MANAGER
1
2
WORKER
In this example, project 1 has two participants, user 1 is there, with the role of a manager, user 2 is there with the role of a worker. In project 2, there is only one participant, user 1, which is in the role of a manager and a worker.
What I want to accomplish is a Java representation like this:
#Entity(...)
class ProjectRole {
// some annotations
private User user;
// some annotations
private Project project;
// some annotations
private Set<String> roles;
// getters and setters
}
I'm aware of two indirect ways to get such an object.
Alternative 1: Map an Entity of the table with:
#Id
#ManyToOne
#JoinColumn(name = "user_id")
User user;
#Id
#ManyToOne
#JoinColumn(name = "project_id")
Project project;
#Id
String role;
and combine multiple hits for the same user (per project) and map it to an object like the wanted structure above, but this would not allow to use sortings or pagination in the future and it would be nice to get the target structure directly.
Alternative 2: I could create an artifical Table participants with an artifical participant.id and use this in an participant_roles table. So I get two entities, while the first one can have a Set<ParticipantRole>. But I have to save a lot of unnecessary information in the database.
Maybe it is impossible, since an Entity-instance is more or less a representation of a row in the database, so I will always get multiple entries per user (per project). Or is there something I haven't seen so far to accomplish it?
Just use the option 1 and expose the details through some dedicated method that does the grouping on-demand or in a #PostLoad event listener. Hibernate/JPA needs the information to be bidirectional and the kind of mapping you want here is more or less a projection of the normalized data.
I start a project with spring boot, I use a database with 6 tables.
It is a CRUD application .
So , I have my entities/dto/service/controller/repository packages for 5 tables. (6 tables in SQL)
Now, I would like to update a row on the column of table x(SQL) of entity x to another entity y at a specific row.
In my opinion, it should be done at the service layer at create X, but how?
Should I create a xyDTO with data from 2 entities? I am afraid of doing it , the table y it doesn't update automatically.But when create the xyDTO. I don't want this.
How I can update the data of specific DTO x to another DTO y (6th table of SQL), at the same time
I cannot find similar example online. Could anyone help me?
My code:
#Entity
#Table(name = "repo")
public class Repo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Long id;
#Column(name="stock")
private Long stock;
}
#Entity
#Table(name = "voucher")
public class Voucher {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "quantity")
private BigDecimal quantity;
#Column(name = "type")
private boolean type;
}
#Service
public class VoucherService{
#Override
public Voucher dtoToEntity(VoucherDTO dto) {
Voucher voucher = new Voucher();
voucher.setId(dto.getId());
voucher.setDescription(dto.getDescription());
List<VoucherProduct> voucherList = new ArrayList<>();
for (VoucherProductDTOMini inv : dto.getVoucherproducts()) {
VoucherProduct voucherL = voucherProductService.DTOtoEntity(inv);
voucherList.add(voucherL);
}
voucher.setVoucherproducts(voucherList);
return voucher;
}
#Override
public VoucherDTO createVoucher(VoucherDTO voucherDTO) {
Voucher voucher=new Voucher();
voucher=voucherRepository.save(voucher);
VoucherDTO voucherDTOnew=new VoucherDTO(voucher);
return voucherDTOnew;
}
}
I should
check the type of my voucher (true), and I should add on my repo entity at
stock.
In which way can I update the two entities at the same time?
When I add a true voucher, I should add on my repo.stock the data of voucher.quantity.
First, I would like to highlight a few things in your code:
I cannot find the reason to use #Override annotation on those methods in your Service.
In createVoucher method you create completely empty entity, this is not a good thing to do.
DTO stands for Data Transfer Object, and usually in Spring applications it is used to transfer data to or from the service. For example: Controllers. When user makes a Http Request to receive all Vouchers for example, you would like to return VoucherDto with only those fields that you want users to see.
You can have different DTO objects for Getting entity values and Updating them. Because sometimes you want to allow users to update only certain properties.
To answer your question on how to update two entities in a single call. As I understood your question, you want to update different properties in two different entities via a single request. This is possible, though there are different approaches to this.
Create two different DTOs, one for each entity. Create two different Http Requests each would take one DTO and call a method in a service to update each Entity. ex.: VoucherController.updateVoucher -> VoucherService.updateVoucher and RepoController.updateRepo -> RepoService.updateRepo. I personally prefer this as a solution because your entities Voucher and Repo don't have any relation.
Create a single DTO object, containing all fields required to be updated, then in the service method find your Voucher, and Repo and update their fields, then save both entities. This would be a messy approach when you have many entities.
There would be another different approach if you would have a relation between your Repo and Voucher entities, for example a OneToMany.
Let me know whether this answers your question. There is nothing wrong to have many DTO objects and Services, etc.
If you would like to easily generate all the DTO objects, have a look at this: https://github.com/OpenAPITools/openapi-generator
I have an old database where there are two tables with implicit association between them:
booking
- id
- name
... some other fields...
and
booking_info
- id
- booking_id
... some other fields...
Due to the current database design there no any constraints between these two tables, which means that one booking entry may exist without any booking_info entries and vice versa. booking_id in booking_info table is an implicit foreign key which refers to booking table (column id), but it also may refer to the absent booking.
I have created the following JPA mapping for these tables:
#Entity
public class Booking {
#Id
private Long id;
private String name;
// getters & setters
}
and
#Entity
public class BookingInfo {
#Id
private Long id;
#OneToOne
#JoinColumn(name = "booking_id")
private Booking booking
// getters & setters
}
Now I need to be able to persist a BookingInfo entity even if there's no related Booking entry in the database.
BookingInfo bookingInfo = new BookingInfo();
bookingInfo.setId(1);
Booking booking = new Booking();
booking.setId(182); // let's say that there's no booking with id 182 in my database, but I still need to persist this bookingInfo
bookingInfo.setBooking(booking);
bookingInfoRepository.save(bookingInfo); // using Spring Data JPA
If I run this code then I get javax.persistence.EntityNotFoundException since booking with id 182 is absent.
What would be the proper workaround for my case using JPA or Hibernate.
Btw, I also tried to use Hibernate's #NotFound annotation. As a result, save method doesn't throw javax.persistence.EntityNotFoundException and entity gets persisted int the database, but the problem is that booking_id in the database always null.
Any help would be appreciated.
I am not sure my answer will help you or not, but the result you are getting perfectly make sense. As you are setting a JPA object, and that object is not present, hence the null value is saved.
If you want to save 182 as an integer, you don't do JPA relationship. Instead, you just use booking-id as an integer field in booking-info. And that makes sense because you actually do not have the relationship between those tables which the JPA is trying to achieve.
But I am sure you just want to save 182 and as well as maintain the JPA relationship. And I am sure you already know it, but DB integrity is not being maintained with the approach you are taking. I am sure there is enough reason behind that. But my recommendation would be applying proper constraints in the DB and then in JPA.
I have a form to add new Appartments, and in this form I have a dropdown where the user can choose what Person is responsible.
Apparantly my application thinks that the Person is modified when you select from the dropdown and try to save the Appartment. And it gives me the error below indicating i should save the Person first. But the Person is not modified. It is only the Appartment that should be saved with a reference to a different Person.
object is an unsaved transient instance - save the transient instance before merging
How can I make my application understand that the Person himself has not been modified. Only the Appartment?
Here is my code:
#Entity
#Table(name = "Person")
public class Person{
#Id
private Long id;
private String fullName;
....
}
#Entity
#Table(name = "Appartment")
public class Appartment{
....
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn (name = "client_contact_person_id")
private Person clientResponsiblePerson;
}
The action loads all Persons into a List responsiblePersons.
And the JSP:
<s:select name="appartment.clientResponsiblePerson.id" list="responsiblePersons"
listKey="id" listValue="fullName" headerKey="-1"
label="%{getText('appartment.clientContact.ourContact')}" headerValue="%{getText('person.choose')}"
required="true" cssClass="select medium" />
Any ideas? I've been searching and debugging for hours without any solution... :(
UPDATE:
Steven suggested that i remove the id from appartment.clientResponsiblePerson.id. This is a reasonable suggestion. I did just try it, but then it seems like my Application dont know how to map the value submitted by the form to a Person-object. As im setting listKey="id" the value submitted is the Person's ID.
I recieve the following errors:
Invalid field value for field "appartment.clientResponsiblePerson".
tag 'select', field 'list', name 'appartment.clientResponsiblePerson': The requested list key 'responsiblePeople' could not be resolved as a collection/array/map/enumeration/iterator type. Example: people or people.{name} - [unknown location]
So my initial thought was that maybe i should delete the listKey and listValue from my s:select. Maybe struts automagically detects the id from the object and uses toString for value? But I tried this as well without any more luck.
Another really strange thing is that I do the exact same thing in another form. In that form i am selecting Areas from a dropdown. And I am using appartment.area.id for name. And it works perfectly there. Strange.. I also checked that the Area - Appartment reference was not set up to automaticly persist or merge.
It strikes me that what i am trying to achive should be really straigh forward. What is it that i am not getting here?
Apparantly my application thinks that the Person is modified when you select from the dropdown and try to save the Appartment.
That's exactly what your code is doing. The following line is the culprit:
appartment.clientResponsiblePerson.id
That is telling the Struts2 framework to take the id of the person you selected in your drop down and pass it to getAppartment().getClientResponsiblePerson().setId(id). That doesn't change to a new responsible person, it changes the primary key for the existing person. Calling setClientResponsiblePerson(Person) would change the person.
Try using appartment.clientResponsiblePerson instead and see how that works for you.
Update
Another really strange thing is that I do the exact same thing in another form.
I don't see how that would work either.
Struts2 doesn't know what a Person is, so you have a few options:
Create a type converter to tell Struts2 how to convert from "1" (or whatever is passed in from your dropdown) to an instance of a Person.
Add a setPerson(Integer) method on your action which will look up the appropriate Person entity based on the Integer primary key passed in and then update your s:select to <s:select name="person" list="responsiblePersons" .../>
Personally, I use #1.
I am trying to establish a relationship between 2 entities which would be zero-to-one. That is, the Parent can be saved without the associated Child entity and also along with the assoicated Child.
Following are the 2 Entity classes...
Employee (Parent)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name="EMP_NAME")
private String name;
#PrimaryKeyJoinColumn
#OneToOne(cascade = {CascadeType.ALL})
private EmployeeInfo info;
#Column(name="EMP_ENUM")
private Integer enumId;
EmployeeInfo (Child)
public class EmployeeInfo {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="EMPLOYEE_EMAIL")
private String email;
With such kind of a relation and id column of the only Parent (Employee) table set to AUTO INCREMENT in MySql DB, the problem is that while saving a Parent->Child object graph, I get the following exception
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [insert into EMP_INFO
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
I tried setting the Child Table's Id property to AUTO INCREMENT in the DB , and the persistence of such a Parent->Child object graph is successful.
However, the problem described here surfaces, because I have a scenario in which I would like to save the parent (Employee) object without the associated EmpInfo object, and hence do NOT want to have AUTO INCREMENT on the Child's id column.
One solution could be not use the PrimaryKeyJoinColumn, but use a particular JoinColumn, but that adds an unnecessary column to my existing Table.
Has anyone come across such a problem? If yes, any pointers would be much helpful.
Finally, I got it working thanks to Pascal and some googling from my side. Apparently, I cannot use the Native key generator for such relationships where the parent can exist without the child (optional = true).
The thing that worked finally was the following, leaving me the downside of having to deal with Hibernate specific annotation (#GenericGenerator) and also having to make-do with bi-directional relationships instead of the unidirectional that I wanted.
Employee (Parent) class remains unchanged as above. It has AUTO INCREMENT on the Id column.
As for the child class (EmployeeInfo) it changed to the following, and again WITHOUT having the AUTO INCREMENT set on the Id column.
#Table(name="EMP_INFO")
#Entity
public class EmployeeInfo {
#Id
#GeneratedValue(generator="foreign")
#GenericGenerator(name="foreign", strategy = "foreign", parameters={
#Parameter(name="property", value="verifInfo")})
private Long id;
#OneToOne(optional=false)
#JoinColumn (name="id")
private Employee emp;
#Column(name="EMPLOYEE_EMAIL")
private String email;
This helped me achieve what I wanted but on the downside, GenericGenerator is not a JPA annotation, it is a hibernate annotation, and sadly I have to make do with that as of now because JPA does not currently support this(or any similar) annotation.
Anyway, it helps to get through such cases :-)
I have a scenario in which I would like to save the parent (Employee) object without the associated EmpInfo object.
The optional attribute of a OneToOne is true by default, which is what you want.
However, you are somehow misusing the #PrimaryKeyJoinColumn here (well, it actually depends on what you really want to achieve but your current combination of annotations is not correct).
IF you want to map a OneToOne with a shared primary-key, use the #PrimaryKeyJoinColumn. But in that case, don't use a GeneratedValue on EmployeeInfo and set the id manually or, if you don't want to set it manually, use the Hibernate specific foreign generator that I already mentioned in your previous question. Check also the related question mentioned below.
And IF you do not want to use a shared primary key (like in your current code since you're trying to get the id generated by the database), then do not use the PrimaryKeyJoinColumn.
You have to make a choice.
References
JPA 1.0 specification:
9.1.32 PrimaryKeyJoinColumn Annotation
Related question
JPA Hibernate One-to-One relationship.