I'm trying to delete User entity from DB
//whatever
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
private Set<Filter> filters = new HashSet<Filter>();
//whatever
//whatever
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH})
#JoinColumn(name = "user_id", nullable = false)
private User user;
//whatever
but getting:
ERROR SqlExceptionHelper:146 - Cannot delete or update a parent row: a foreign key constraint fails (web_app_db.filters, CONSTRAINT FK_8oeay5yddrcgd4i71m1yda1hb FOREIGN KEY (user_id) REFERENCES users (user_id))
orphanRemoval = true not working, what should I do?
Try this:
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinColumn(name = "user_id", nullable = false)
private User user;
Related
I'm running into a very annoying issue whereby an entity loses its state after the object is merged into the EntityManager.
In the application there's a "Dossier" with ExpenditureStatements which has a number of expenditures.
These expenditures can be (partially) claimed from multiple debtors.
An ExpenditureStatementClaim is created for the ExpenditureStatement.
An ExpenditureClaim is created for each Expenditure on the ExpenditureStatement.
Both the ExpenditureClaims and the ExpenditureStatementClaim are persisted without any issues.
The expenditures however lose their state after the merge on the entitymanager is called:
em.merge(dossier).
However, the data in each expenditure reverts back to its last state in the database.
I've already tried cascading only top down, i've made changes to equals/hashcode but this didn't change anything.
Does anyone have a clue as to what might be causing this issue?
Dossier:
#Entity
#Table(name = "DOSSIER")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DOSSIER_TYPE", discriminatorType = DiscriminatorType.STRING, length = 48)
public abstract class Dossier {
#OneToMany(mappedBy = ExpenditureStatement.PROP_DOSSIER, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<ExpenditureStatement> expenditureStatements = new ArrayList<ExpenditureStatement>();
}
ExpenditureStatement:
#Entity
#Table(name = "EXPENDITURE_STATEMENT")
public class ExpenditureStatement {
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
#JoinColumn(name = "DOSSIER_ID", nullable = false)
private Dossier dossier;
#OneToMany(mappedBy = Expenditure.PROP_EXPENDITURE_STATEMENT, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<Expenditure> expenditures = new ArrayList<Expenditure>();
#OneToMany(mappedBy = ExpenditureStatementClaim.PROP_EXPENDITURE_STATEMENT, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<ExpenditureStatementClaim> expenditureStatementClaims = new ArrayList<ExpenditureStatementClaim>();
}
Expenditure:
#Entity
#Table(name = "EXPENDITURE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "EXPENDITURE_ORIGIN_CD", discriminatorType = DiscriminatorType.STRING, length = 48)
public abstract class Expenditure extends EntityObject<Long> {
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "EXPENDITURE_STATEMENT_ID", nullable = false)
private ExpenditureStatement expenditureStatement;
#OneToMany(mappedBy = ExpenditureClaim.PROP_EXPENDITURE, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<ExpenditureClaim> claims = new HashSet<>();
#NotNull
#Column(name = "EXPENDITURE_STATUS_CD", nullable = false)
#Enumerated(EnumType.STRING)
private ExpenditureStatus status;
public abstract BigDecimal getAmount();
}
ExpenditureStatementClaim:
#Entity
#Table(name = "DEEL_STAAT")
public class ExpenditureStatementClaim {
#NotNull
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
#JoinColumn(name = "EXPENDITURE_STATEMENT_ID", nullable = false)
private ExpenditureStatement expenditureStatement;
#OneToMany(mappedBy = ExpenditureClaim.PROP_EXPENDITURE_STATEMENT_CLAIM, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<ExpenditureClaim> expenditureClaims = new ArrayList<>();
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "INVOICE_ID")
private Invoice invoice;
}
ExpenditureClaim:
#Entity
#Table(name = "EXPENDITURE_CLAIM")
public class ExpenditureClaim extends EntityObject<Long> {
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "EXPENDITURE_ID", nullable = false)
private Expenditure expenditure;
#Column(name = "AMOUNT", precision = NumberConstants.CURRENCY_PRECISION, scale = NumberConstants.CURRENCY_OPERATION_SCALE)
private BigDecimal amount;
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "EXPENDITURE_ST_CLAIM_ID", nullable = false)
private ExpenditureStatementClaim expenditureStatementClaim;
}
The issue was not caused by a problem with the mapping, but due to a bug in the (quite old) version of EclipseLink the project was using, whereby a newly created object would not cascade changes made to an already existing object.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=340802
Just a good reminder that whenever possible you should try to update the version of the dependencies in your project...
I have three tables. tbl_vendor and tbl_category tables are mapped using #ManyToMany relation. When I am getting 'Vendors' under a particular 'Category' I am also getting 'Areas' because tbl_vendor and tbl_area are also mapped using #ManyToMany.
relations:
in tbl_vendor Model :
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_category_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "category_id")})
private Set<Category> categories = new HashSet<>();
....
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_area_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "area_id")})
private Set<Area> areas = new HashSet<>();
in tbl_category Model :
#JsonIgnore
#ManyToMany(cascade = CascadeType.DETACH, mappedBy = "categories", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
in tbl_area Model :
#JsonIgnore
#ManyToMany(mappedBy = "areas", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
I have a particular case where I don't need this 'Area' with 'Vendor'.
is there any way to ignore already mapped 'Area' from 'Vendor' using JpaRepository in some particular case ?
I have a LibraryModel class, a LibraryImage class and a LibraryAttribute class. A LibraryModel can have an arbitrary number of LibraryImages and LibraryAttributes.
The error that I get:
org.hibernate.MappingException: Foreign key (FKmbn4xh7xdxv371ao5verqueu3:library_item_attribute [LIBRARY_ITEM_ATTRIBUTE_ID])) must have same number of columns as the referenced primary key (library_item_attribute [LIBRARY_ITEM_ID,LIBRARY_ITEM_ATTRIBUTE_ID])
Here are my annotated Objects:
Library Model:
#Entity
#Table(name = "library_item", uniqueConstraints = {
})
#Inheritance(strategy = InheritanceType.JOINED)
public class LibraryItemModel implements LibraryItem{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_ITEM_ID", unique = true, nullable = false)
private Integer libraryItemId;
#Column(name = "ITEM_TITLE", unique = false, nullable = false)
private String itemTitle;
#Column(name = "IS_PARENT", nullable = false)
private Boolean isParent;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ID", nullable = false)
private LibraryModel libraryModel;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "ITEM_LISTING",
joinColumns = {#JoinColumn(name = "PARENT_LIB_ITEM_ID", nullable=false)},
inverseJoinColumns = {#JoinColumn(name="CHILD_LIB_ITEM_ID", nullable = false)})
private Set<LibraryItemModel> itemChildren = new HashSet<>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "itemChildren")
private Set<LibraryItemModel> itemParents = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "LIBRARY_ITEM_IMAGE",
joinColumns = { #JoinColumn(name = "LIBRARY_ITEM_ID", nullable=false)},
inverseJoinColumns = { #JoinColumn(name="LIBRARY_IMAGE_ID", nullable = false)})
private Set<LibraryImage> itemImages = new HashSet<>();
#OneToMany(fetch = FetchType.LAZY, mappedBy = "rootLibraryItemModel")
private Set<LibraryModel> libraries = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "LIBRARY_ITEM_ATTRIBUTE",
joinColumns = { #JoinColumn(name = "LIBRARY_ITEM_ID", nullable =false)},
inverseJoinColumns = { #JoinColumn(name="LIBRARY_ITEM_ATTRIBUTE_ID", nullable = false)})
private Set<LibraryItemAttribute> libraryItemAttributes = new HashSet<>();
}
LibraryImage:
#Entity
#Table(name = "library_image", uniqueConstraints = {
})
public class LibraryImage {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_IMAGE_ID", unique = true, nullable = false)
private Integer libraryImageId;
#Column(name = "IMAGE_LOCATION")
private String imageLocation;
#Column(name = "IMAGE_TITLE")
private String imageTitle;
#Enumerated(EnumType.STRING)
private LibraryImageType imageType;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ITEM_ID", nullable = false)
private LibraryItemModel libraryItemModel;
}
Library Attribute:
#Entity
#Table(name = "library_item_attribute", uniqueConstraints = {
})
public class LibraryItemAttribute {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_ITEM_ATTRIBUTE_ID", unique = true, nullable = false)
private Integer libraryItemAttributeId;
#Column(name = "ATTRIBUTE_NAME")
private String attributeName;
#Column(name = "ATTRIBUTE_VALUE")
private String attributeValue;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ITEM_ID", nullable = false)
private LibraryItemModel libraryItemModel;
}
This is really frustrating as the LibraryImage class is mapped without problems and doesn't throw any errors, but the LibraryAttribute class which is annotated in an identical way to the LibraryImage class is throwing this error.
Can someone please have a look and let me know what my problem is?
Found the problem.
In the LibraryItemModel class I defined the Join table with the LibraryItemAttribute to be called "LIBRARY_ITEM_ATTRIBUTE", which is the name of the table of the Library item attributes.
The join table is a different table and should have a different table name.
For the Library Image table above, the image table is called library_image, while the join table is called LIBRARY_ITEM_IMAGE
#Entity
public class Conference {
#ManyToOne
#JoinColumn(name = "host_id")
#JsonManagedReference
private User host;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "PARTICIPANT_CONFERENCE",
joinColumns = #JoinColumn(name = "CONFERENCE_ID_FRK"),
inverseJoinColumns = #JoinColumn(name = "PARTICIPANT_ID_FRK")
)
#JsonManagedReference
private Set<User> participants;
}
#Entity
public class User {
#ManyToMany(
targetEntity = Conference.class,
fetch = FetchType.EAGER,
cascade = CascadeType.REMOVE,
mappedBy = "participants"
)
#JsonBackReference
private Set<Conference> conferenceSet;
#OneToMany(
targetEntity = Conference.class,
mappedBy = "host",
cascade = CascadeType.REMOVE,
fetch = FetchType.EAGER
)
#JsonBackReference
private Set<Conference> conferenceHostSet;
}
I used JPA and have a problem that OneTOMany field does not update in JPA.
If I added host in Conference, but User's host set did not update.
So, I tried to update User's host set, too.
Set<Conference> conferences = form.getHost().getConferenceHostSet();
conferences.add(conference);
userRepository.save(form.getHost().setConferenceSet(conferences));
It works well, but User's participant set also updated.
How can I update only host?
You have set cascading to only work for "remove" you need to set it up for all of the actions you want.
I used seam to generate my entities. But I have a many to many composite table with an employee id and a vehicle id and it generated the hash sets wrong. I want to be able to choose an employee's favorite vehicle in the employee object. However; when I add things to the hashset in the employee object and persist it, it does not add anything to the composite table. The vehicle object has the
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "flower_store_emp_vehicle", schema = "dbo", catalog = "tyler", joinColumns = { #JoinColumn(name = "vehicle_id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "employee_id", nullable = false, updatable = false) })
and the employee object has the:
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "flowerStoreEmployees")
I am guessing these are backwards, however; I am new to seam and do not how to switch them around without the mappedBy being all wrong. If anyone knows how to help it would be greatly appreciated. Thank you
If you want the employee to be the owner of the association, just switch the annotations:
Employee:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "flower_store_emp_vehicle",
schema = "dbo",
catalog = "tyler",
inverseJoinColumns = { #JoinColumn(name = "vehicle_id", nullable = false, updatable = false) },
joinColumns = { #JoinColumn(name = "employee_id", nullable = false, updatable = false) })
private Set<Vehicle> vehicles;
Vehicle:
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "vehicles")
private Set<Employee> employees;