I have 3 objects with simple relationship which looks as follows:
University:
#Entity
public class University {
#Id
#GeneratedValue
private Long id;
private String name;
}
Faculty:
#Entity
public class Faculty {
#Id
#GeneratedValue
private Long id;
private String name;
#Column(name = "university_id", nullable = false)
private Long universityId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinFetch(value = JoinFetchType.OUTER)
#JoinColumn(name = "university_id", insertable = false, updatable = false, nullable = false)
private University university;
}
Specialty:
#Entity
public class Specialty {
#Id
#GeneratedValue
private Long id;
private String name;
#Column(name = "faculty_id", nullable = false)
private Long facultyId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinFetch(value = JoinFetchType.OUTER)
#JoinColumn(name = "faculty_id", insertable = false, updatable = false, nullable = false)
private Faculty faculty;
}
I am using EclipseLink and Spring CrudRepository to operate with these entities.
When i call
specialtyRepository.findAll();
i get sql
SELECT * FROM specialty LEFT OUTER JOIN faculty ON (faculty.ID = specialty.faculty_id) ...
and extra sql like
SELECT * FROM university WHERE ((ID = ?)) ...
I want to prevent this sql request;
Could someone tell me how to resolve this issue?
Thank you for any tips
For lazy loading in #ManyToOne i must enable dynamic weaving in EclipseLink:
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving
I solved this problem via inheritance;
I have created the base instance without relationship;
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class FacultyBase {
#Id
#GeneratedValue
private Long id;
private String name;
#Column(name = "university_id", nullable = false)
private Long universityId;
}
and instance with relationship
#Entity
public class Faculty extends Faculty {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "university_id", insertable = false, updatable = false, nullable = false)
private University university;
}
As a result, in Specialty instance i use FacultyBase instead of Faculty
Related
I am studying a training project - working with databases.
Here is a class describing the entity
#Entity
#Table(name = "pricelists", schema = "inventories")
public class PriceList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "id_inventory", insertable = false, updatable = false)
private Long idInventory;
#ManyToOne
#JoinColumn(name = "id_inventory", nullable = false)
private Inventory inventory;
private Integer price;
}
And there are two variables that refer to the same "id_inventory" field in the database table. Is it possible to do this? Is this not a mistake?
You should leave that
#Entity
#Table(name = "pricelists", schema = "inventories")
public class PriceList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "id_inventory", nullable = false)
private Inventory inventory;
private Integer price;
}
I hope that will work.
The "TypeMismatchException: Provided id of the wrong type" error thrown when tried to merge detached entity. It works if the object wasn't detached. It also works if ids aren't #EmbeddedId.
A sample repo can be found here https://github.com/joes-code/hibernate-map
// Asset.java
#Entity
#Table(name = "asset")
public class Asset {
#EmbeddedId
private AssetId id;
#Column(name = "asset_cost"
private BigDecimal price;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "asset_id", referencedColumnName = "asset_id", nullable = false, insertable = false, updatable = false, foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))
private AssetDetail assetDetail;
}
// AssetId.java
#Embeddable
public class AssetId {
#Column(name = "asset_id", nullable = false)
private Integer assetId;
}
// AssetDetail.java
#Entity
#Table(name = "asset_detail")
public class AssetDetail {
#EmbeddedId
private AssetDetailId id;
#Column(name = "description", length = 35)
private String description;
}
// AssetDetailId.java
#Embeddable
public class AssetDetailId {
#Column(name = "asset_id", nullable = false)
private Integer assetId;
}
I'm using Hibernate 5.4.3.Final
Any ideas what I did wrong? It seems that Hibernate is assuming Asset and AssetDetail share the same Id class?
I want to make connection between Product class and Laptop
Product class
#Entity
#Table(name = "products")
#Inheritance(strategy = InheritanceType.JOINED)
public class Product {
#Id
#Column(unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(nullable = false, unique = true)
private String name;
#Column(nullable = false)
private BigDecimal cost;
#Column(nullable = false)
private int count;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "productStatus", nullable = false)
private ProductStatus productStatus;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "productManufacture", nullable = false)
private ProductManufacture productManufacture;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "productCategory", nullable = false)
private ProductCategory productCategory;
and
Laptop class
#Entity
#Table(name = "laptops")
public class Laptop extends Product {
#Id
#Column(unique = true, nullable = false)
private int id;
#Column(nullable = false)
private String processor;
private int videoMemory;
#Column(nullable = false)
private int ram;
But my varient doesnt work...( How can I do it right
And how can I insert into database some data?(example please)
Laptop is extending Product class and inherits all the fields from the parent class including ID. You are defining ID again on the Laptop class. Inheritance Strategy is also JOINED which means it handles the Id generation both for the parent and the child class. Remove the Id field and its annotations.
We have a Java ee application running on JBoss 6.4 GA using JPA and Hibernate with the following entities:
#Entity
#SequenceGenerator(name = "sequence", sequenceName="SEQ_CAMPAIGNS_ID",allocationSize = 1)
#Table(name = "CAMPAIGN")
public class CampaignEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "IS_ACTIVE", nullable = false)
private boolean active;
#Column(name = "START_DATE", nullable = false)
private Date startDate;
#Column(name = "END_DATE", nullable = false)
private Date endDate;
#Column(name = "LEGAL_ENTITY_ID", nullable = false)
private Integer legalEntityId;
#Column(name = "DEPARTMENT", nullable = false)
#Enumerated(value = EnumType.STRING)
private Department department;
#Column(name = "CATEGORY", nullable = false)
#Enumerated(value = EnumType.STRING)
private Category category;
#Embedded
CampaignConditionsEntity campaignConditions;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "campaign", orphanRemoval = true)
#OrderBy
private List<CodeEntity> campaignCodes;
public CampaignEntity() {
}
And the following CampaignConditionsEntity:
#Embeddable
public class CampaignConditionsEntity implements Serializable {
private static final String CAMPAIGN_ID = "CAMPAIGN_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CAMPAIGN_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CAMPAIGN_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
And the following CodeEntity:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#SequenceGenerator(name = "sequence", sequenceName = "SEQ_CODES_ID", allocationSize = 1)
public abstract class CodeEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CAMPAIGN_ID")
private CampaignEntity campaign;
#OneToOne(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private DiscountEntity discount;
#Column(name = "MAX_USAGES", nullable = false)
private Integer maxUsages;
#Column(name = "UNLIMITED_USAGES", nullable = false)
private boolean unlimitedUsages;
#Column(name = "NEGATIVE_SH", nullable = false)
private boolean negativeSH;
#Column(name = "UNIQUE_BUYER", nullable = false)
private boolean uniqueBuyer;
#Column(name = "START_DATE")
private Date startDate;
#Column(name = "END_DATE")
private Date endDate;
#Embedded
private CodeConditionsEntity codeConditions;
public CodeEntity() {
}
This is the CodeConditionsEntity:
#Embeddable
public class CodeConditionsEntity implements Serializable {
private static final String CODE_ID = "CODE_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CODE_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_CARRIERS", joinColumns = #JoinColumn(name = CODE_ID))
private Set<CarrierConditionEntity> carrierConditions;
This is the CarrierConditionEntity:
#Embeddable
public class CarrierConditionEntity implements Serializable {
#Column(name = "CARRIER", nullable = false, length = 3)
private String carrierCode;
#Column(name = "IS_INCLUDED", nullable = false)
private boolean included;
The problem is that in the logs we are finding unexpected deletes when the only operation that we are doing are finds of particular campaign entities.
In the production logs we find the following deletes
Hibernate: delete from CODE_COND_CARRIERS where CODE_ID=? and CARRIER=? and IS_INCLUDED=?
do you have any suggestion?
thanks
I have some suggestions :)
Be aware of what is a Persistence Context (EntityManager instance in JPA terminology / Session in Hibernate one), the entity lifecycle and transaction scope (unit of work)
Do not mutate entity state if you don't expect the changes to be reflected in database, or at least detach the entity before mutating it.
Mark your transaction as "readOnly" if you only fetch data in the related unit of work. (beware that if you have many "Transactional" methods joining the same physical transaction, the flag is set by the surrounding one and cannot be overridden by inner logical transactions). That way the EntityManager won't be flushed at the end of the transaction and pending changes won't be persisted to the database.
You can track the method triggering the unexpected deletion using an EntityListener on the related entity and printing the current strackTrace (new Throwable().printStackTrace()/ log(new Throwable()) in the PreRemove method
I found where was the problem:
The problem was that the Entities didn't have the equals() and the hashcode() implemented. Also there were entities that have a #PostLoad that modified the entity after loading it from database. Then in this situation Hibernate though that there was a change in those entities that didn't have the equals and the hashcode, and then it delete all of them and inserted again in the database (to have the same entities before the query)
Adding the equals and hashcode methods and deleting postload removed the unexpected deletes and inserts from the logs.
regards
I have a performance issue with the following Hibernate TypedQuery:
select generatedAlias0 from MyClass1 as generatedAlias0
where generatedAlias0.class2.uid in (:param0, ..., :paramN)
Following the actual implementation this results in the following query:
select myclass1_.id, myclass1_.other, ... # 16 fields in total, no special big ones
from myschema.dbo.TblMyClass1 myclass1_ cross join myschema.dbo.TblMyClass2 myclass2_
where myclass1_.myclass2Id=myclass2.Id and (myclass2_.uid in('value1', ... 'valueN'))
Where N each time stands for 384 items.
When I execute this query in Toad it only takes about 150ms, but executed from code it takes almost a minute!
Class mappings
#Entity
#Table(name = "TblMyClass1", catalog = "myschema", schema = "dbo")
public class MyClass1 implements Serializable {
private static final long serialVersionUID = 8208493383744288872L;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
protected Integer id;
#NotNull
#ManyToOne
#JoinColumn(name = "myclass2Id", referencedColumnName = "Id", nullable = false)
private MyClass2 class2 = null;
#NotNull
#ManyToOne
#JoinColumn(name = "myclass3Id", referencedColumnName = "Id", nullable = false)
private MyClass3 class3 = null;
#NotNull
#ManyToOne
#JoinColumn(name = "myClass4Id", referencedColumnName = "Id", nullable = false)
private MyClass4 myClass4;
#ManyToOne
#JoinColumn(name = "myClass5Uid", referencedColumnName = "UID", nullable = true)
private MyClass5 resultType;
#Column(name = "string2", nullable = true)
private String string2;
// other column fields and getters and setters ...
}
#Entity
#Table(name = "TblMyClass2", schema = "myschema", catalog = "dbo")
public final class MyCLass2 implements Serializable {
private static final long serialVersionUID = 4660579327140751989L;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
protected Integer id;
#Column(name = "uid", nullable = false, updatable = false, unique = true)
private String uid;
// ... other columns fields and getters and setters
}
I only provided the mappings for the two classes in the slow query, since the follow-up queries of hibernate which fill all other linked entities all perform very good.
Using Java VisualVm I find that the following method takes 99% of the time:
com.microsoft.sqlserver.jdbc.TDSChannel.read()
I am running SQL Server 2008 and using sqljdbc4-2.0 and hibernate4.2.1 with spring3.2.9 (for transaction management)
Any help would be greatly appreciated !